雨天的尾巴

来源:互联网 发布:百分百营销软件站 编辑:程序博客网 时间:2024/04/26 01:23

题目大意

给定一棵n个点的树。有m个操作,每个操作给出x,y,z,然后对于点x 到点y 的路径上(含x 和y) 每个点对应数值为z的数的个数+1。
最后输出每个点个数最多的数的数值(个数相同输出数值较小值)。

数据范围 n,m <= 100000,z<=10^9。

树链剖分,复杂度O(nlogn2)

(werkeytom大神用线段树合并O(n log n)解决)
z比较大,但最多也就m种,所以我们先离散化z。
首先考虑序列上的做法,对于一个操作x,y,z(离散化后的),我们拆成两个操作
1:a=x,z,b=1;2:a=y+1,z,b=-1。然后把操作按a值排序。
然后我们O(n)扫一遍每个位置,把每个位置上的操作都处理掉,每个操作为数值为z的数的个数+b,用线段树维护数值为z的数的个数,那么当前位置的答案我们可以直接得出。修改操作复杂度为O(log n),总复杂度O(n log n)。
树上的怎么做呢?我们可以树链剖分一下,每条链都是一段序列,所以我们可以把操作拆开,一个操作最多拆log n次,然后剩下的按序列上的做,总时间O(nlogn2)

代码

#include<cstdio>#include<algorithm>#include<cstring>#define ll long longusing namespace std;const int maxn=100000+5;int tree[maxn*4],p[maxn],tr[maxn*4],t,n,m,k[maxn],c[maxn],next[maxn*2],g[maxn*2],num,s[maxn],son[maxn],b[maxn],a[maxn],qx[maxn],qy[maxn],ans[maxn],q[maxn],fa[maxn],f[maxn],d[maxn],bz[maxn],bk[maxn],cnt[maxn*36][3];void add(int x,int y){    next[++num]=k[x];    k[x]=num;    g[num]=y;}void read(int &n){    char ch=getchar();    while(ch!='-'&&(ch<'0')||(ch>'9'))ch=getchar();n=0;    int q=1;if (ch=='-') ch=getchar(),q=-1;    while(ch>='0'&&ch<='9')n=n*10+ch-'0',ch=getchar();n=n*q;}void dfs(int x,int y){    int i=k[x],s1=0;    s[x]=1;fa[x]=y;f[x]=x;    while (i>0){        if (g[i]!=y) {            d[g[i]]=d[x]+1;            dfs(g[i],x);            s[x]+=s[g[i]];            if (s[g[i]]>s1) s1=s[g[i]],son[x]=g[i];        }        i=next[i];    }}void df(int x,int y){    if (son[y]==x) f[x]=f[y];    b[x]=++num;    a[num]=x;    if (son[x]>0) df(son[x],x);    int i=k[x];    while (i>0){        if (g[i]!=y&&son[x]!=g[i]) df(g[i],x);        i=next[i];    }}void qs(int l,int r){    int i=l,j=r,m=q[(l+r)/2];    while (i<=j){        while (q[i]<m) i++;        while (q[j]>m) j--;        if (i<=j){            swap(q[i],q[j]);            swap(qx[i],qx[j]);            swap(qy[i],qy[j]);             i++;j--;         }     }     if (i<r) qs(i,r);    if (l<j) qs(l,j); }void qss(int l,int r){    int i=l,j=r,m=cnt[(l+r)/2][1];    while (i<=j){        while (cnt[i][1]<m) i++;        while (cnt[j][1]>m) j--;        if (i<=j){            swap(cnt[i],cnt[j]);            i++;j--;         }     }     if (i<r) qss(i,r);    if (l<j) qss(l,j); }void put(int k,int l,int r,int x,int y){    if (l==r) {        tree[k]+=y;        tr[k]=p[l];        return;    }     int m=(l+r)/2;    if (x<=m) put(k*2,l,m,x,y);else    put(k*2+1,m+1,r,x,y);    if (tree[k*2]>=tree[k*2+1]) {        tree[k]=tree[k*2];        tr[k]=tr[k*2];    }else{        tree[k]=tree[k*2+1];        tr[k]=tr[k*2+1];    }}int main(){    read(n);read(m);num=0;    for (int i=1;i<n;i++){        int x,y;read(x);read(y);        add(x,y);add(y,x);    }    dfs(1,0);num=0;    df(1,0);    for (int i=1;i<=m;i++) read(qx[i]),read(qy[i]),read(q[i]);    qs(1,m);q[0]=0;t=0;     for (int i=1;i<=m;i++) if (q[i]>q[i-1]) c[i]=++t,p[t]=q[i];else c[i]=t;         num=0;    for (int i=1;i<=m;i++){        int x=qx[i],y=qy[i];        while (f[x]!=f[y]){            if (d[f[x]]<d[f[y]]) swap(x,y);            num++;cnt[num][0]=c[i];            cnt[num][1]=b[f[x]];cnt[num][2]=1;            num++;cnt[num][0]=c[i];            cnt[num][1]=b[x]+1;cnt[num][2]=-1;             x=fa[f[x]];        }         if (d[x]<d[y]) swap(x,y);        num++;cnt[num][0]=c[i];        cnt[num][1]=b[y];cnt[num][2]=1;        num++;cnt[num][0]=c[i];        cnt[num][1]=b[x]+1;cnt[num][2]=-1;    } qss(1,num);int j=1;    for (int i=1;i<=n;i++){        while (j<=num&&cnt[j][1]==i) put(1,1,t,cnt[j][0],cnt[j][2]),j++;        if (tree[1]>0)ans[a[i]]=tr[1];else ans[a[i]]=0;    }    for (int i=1;i<=n;i++) printf("%d\n",ans[i]);}
0 0
原创粉丝点击