bzoj 4999: This Problem Is Too Simple!

Description

给您一颗树,每个节点有个初始值。
现在支持以下两种操作:
1. C i x(0<=x<2^31) 表示将i节点的值改为x。
2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点。
 

Input

第一行有两个整数N,Q(1 ≤N≤ 100,000;1 ≤Q≤ 200,000),分别表示节点个数和操作个数。
下面一行N个整数,表示初始时每个节点的初始值。
接下来N-1行,每行两个整数x,y,表示x节点与y节点之间有边直接相连(描述一颗树)。
接下来Q行,每行表示一个操作,操作的描述已经在题目描述中给出。
 

 

Output

对于每个Q输出单独一行表示所求的答案。
 

 

Sample Input

5 6
10 20 30 40 50
1 2
1 3
3 4
3 5
Q 2 3 40
C 1 40
Q 2 3 40
Q 4 5 30
C 3 10
Q 4 5 30

Sample Output

0
1
1
0
————————————————————————————
这道题我写的扫描线 
我们把一个询问(u->v)拆成四个 
设根为1 
询问的答案就是1->u + 1->v - 1->lca(u,v) 1-fa[lca] 
然后修改的影响范围只有这个点的子树 这个可以用dfs序+树状数组实现
然后我们每一种权值建一棵树(权值需要离散化) 当然因为如果每次都初始化树状数组肯定会T
这里我利用了时间戳  这样之后就解决问题了 就是代码可能有点复杂QAQ
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
const int M=1e6+7,mod=9875321;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
    return ans*f;
}
int n,m,k,v[M],l[M],r[M],pos[M];
int first[M],cnt,ans[M],mark[M];
struct node{int to,next;}e[2*M];
void ins(int a,int b){e[++cnt]=(node){b,first[a]}; first[a]=cnt;}
void insert(int a,int b){ins(a,b); ins(b,a);}
int dep[M],f[M][25],sum;
void dfs(int x){
    l[x]=pos[x]=++sum;
    for(int i=1;(1<<i)<=dep[x];i++) f[x][i]=f[f[x][i-1]][i-1];
    for(int i=first[x];i;i=e[i].next){
        int now=e[i].to;
        if(!dep[now]){
            dep[now]=dep[x]+1;
            f[now][0]=x;
            dfs(now);
        }
    }r[x]=sum;
}
int find(int x,int y){
    if(dep[x]<dep[y]) std::swap(x,y);
    int d=dep[x]-dep[y];
    for(int i=0;(1<<i)<=d;i++) if(1<<i&d) x=f[x][i];
    if(x==y) return x;
    for(int i=20;i>=0;i--) 
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
struct P{int s,x,T;};
std::vector<P>e1[M];
struct Q{int l,r,T;};
std::vector<Q>e2[M];
int star[mod],cnth;
struct H{int to,next;}hash[M];
int get(int x){
    int w=x%mod;
    for(int i=star[w];i;i=hash[i].next) if(hash[i].to==x) return i;
    cnth++; hash[cnth].to=x; hash[cnth].next=star[w]; star[w]=cnth;
    return cnth;
}
char c[5];
int s[M],now[M];
int lowbit(int x){return x&-x;}
void add(int x,int ss){
    while(x<=n){
        if(now[x]!=k) now[x]=k,s[x]=0;
        s[x]+=ss; 
        x+=lowbit(x);
    }
}
int query(int x){
    int ans=0;
    while(x){
        if(now[x]==k) ans+=s[x];
        x-=lowbit(x);
    }
    return ans;
}
int main(){
    n=read(); m=read();
    for(int i=1;i<=n;i++){
        v[i]=get(read());
        e1[v[i]].push_back((P){1,i,0});
    }
    int x,y;
    for(int i=1;i<n;i++) x=read(),y=read(),insert(x,y);
    dep[1]=1; dfs(1);
    for(int i=1;i<=m;i++){
        scanf("%s",c);
        if(c[0]=='C'){
            x=read(); k=get(read());
            if(v[x]==k) continue;
            e1[k].push_back((P){1,x,i});
            e1[v[x]].push_back((P){-1,x,i});
            v[x]=k;
        }
        else{
            mark[i]=1;
            x=read(); y=read(); k=get(read());
            e2[k].push_back((Q){x,y,i});
        }
    }
    for(k=1;k<=cnth;k++){
        int now=0;
        P* h1=e1[k].data();
        Q* h2=e2[k].data();
        for(int i=0;i<e2[k].size();i++){
            while(now<e1[k].size()&&h1[now].T<=h2[i].T){
                add(l[h1[now].x],h1[now].s);                
                add(r[h1[now].x]+1,-h1[now].s);                
                now++;
            }
            int id=h2[i].T;
            ans[id]+=query(pos[h2[i].l]); ans[id]+=query(pos[h2[i].r]);
            int lca=find(h2[i].l,h2[i].r),fa=f[lca][0];
            ans[id]-=query(pos[lca]); ans[id]-=query(pos[fa]);
        }
    }
    for(int i=1;i<=m;i++)if(mark[i]) printf("%d\n",ans[i]);
    return 0;
}
View Code

 

posted @ 2017-08-30 16:38  友人Aqwq  阅读(...)  评论(...编辑  收藏