【树剖】【树上差分】部落冲突

题目大意

处理下面三件事,所有的事件都是按照时间顺序给出的。

1.(Q p q)从第 p 个部落出发的建筑工人想知道能否到达第 q 个部落了,你要回答的便是(Yes/No),注意大小写
2.(C p q)第 p 个部落与第 q 个部落开战了,保证他们一定是相邻的部落,且目前处于停战(未开战)状态
3.(U x ) 第 x 次发生的战争结束了,它将永远的被载入史册,不复存在(保证这个消息不会告诉你多次)

对于30%的数据 1<=n,m<=6000

对于另30%的数据,保证部落之间的地理关系是一条链,且 i 与 i + 1 之间有一条道路

对于另30%的数据,1<=n,m<=100000

对于100%的数据,1<=n,m<=300000

分析

一道很裸的树剖
但是数据太大卡线段树,用树状数组可以过
用树状数组维护一条链上是否有战争
这个思想可以树上差分
树状数组维护Sum(i)i到root的战争个数
询问Sum(p)+Sum(q)-Sum(Lca(p,q))*2

树剖

#include
#include
#include
#define N 300010
#define fr first
#define se second
#define mp(p,q) make_pair(p,q)
using namespace std;
pair<int,int>b[N<<1];
int num,h[N],d[N],fa[N],sz[N],son[N],top[N],tot,dfn[N],n,m,t[N],p,q,cnt,c[N];
char ch;
int rd(){
    int x=0,y=1;
    char ch;
    while((ch=getchar())<'0'||ch>'9')if(ch=='-')y=-1;
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*y;
}
int lb(int x){
    return x&(-x);
}
void ljb(int p,int q){
    b[++num]=mp(q,h[p]);
    h[p]=num;
}
int Dfs(int x){
    sz[x]=1;
    for(int i=h[x],y=b[i].fr;i;i=b[i].se,y=b[i].fr)if(y!=fa[x]){
        fa[y]=x;
        d[y]=d[x]+1;
        sz[x]+=Dfs(y);
        if(sz[y]>sz[son[x]])son[x]=y;
    }
    return sz[x];
}
void dfs(int x){
    if(x==son[fa[x]])top[x]=top[fa[x]];
    else top[x]=x;
    dfn[x]=++tot;
    if(son[x])dfs(son[x]);
    for(int i=h[x],y=b[i].fr;i;i=b[i].se,y=b[i].fr)if(y!=fa[x]&&y!=son[x])dfs(y);
}
void Ins(int x,int v){
    for(int i=x;i<=n;i+=lb(i))t[i]+=v;
}
int Sum(int x){
    int tmp=0;
    for(int i=x;i>=1;i-=lb(i))tmp+=t[i];
    return tmp;
}
bool Que(int p,int q){
    while(top[p]!=top[q]){
        if(dfn[top[p]]if(Sum(dfn[p])-Sum(dfn[top[p]]-1))return 1;
        p=fa[top[p]];
    }
    if(dfn[p]return Sum(dfn[p])-Sum(dfn[q])?1:0;
}
int main(){
    n=rd(),m=rd();
    for(int i=1;i1),dfs(1);
//  for(int i=1;i<=n;i++)printf("%d ",dfn[i]);
//  printf("\n");
    for(int i=1;i<=m;i++){
        while((ch=getchar())!='C'&&ch!='Q'&&ch!='U');
        if(ch=='C'){
            p=rd(),q=rd();
            if(dfn[p]1);
        }
        else if(ch=='Q'){
            p=rd(),q=rd();
            Que(p,q)?puts("No"):puts("Yes");
        }
        else {
            p=rd();
            Ins(dfn[c[p]],-1);
        }
    }
}

树上差分

#include
#include
#include
#define N 300010
#define fr first
#define se second
#define mp(p,q) make_pair(p,q)
using namespace std;
pair<int,int>b[N<<1];
int num,h[N],d[N],fa[N],sz[N],son[N],top[N],tot,dfn[N],n,m,t[N],p,q,cnt,c[N];
char ch;
int rd(){
    int x=0,y=1;
    char ch;
    while((ch=getchar())<'0'||ch>'9')if(ch=='-')y=-1;
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*y;
}
int lb(int x){
    return x&(-x);
}
void ljb(int p,int q){
    b[++num]=mp(q,h[p]);
    h[p]=num;
}
int Dfs(int x){
    sz[x]=1;
    for(int i=h[x],y=b[i].fr;i;i=b[i].se,y=b[i].fr)if(y!=fa[x]){
        fa[y]=x;
        d[y]=d[x]+1;
        sz[x]+=Dfs(y);
        if(sz[y]>sz[son[x]])son[x]=y;
    }
    return sz[x];
}
void dfs(int x){
    if(x==son[fa[x]])top[x]=top[fa[x]];
    else top[x]=x;
    dfn[x]=++tot;
    if(son[x])dfs(son[x]);
    for(int i=h[x],y=b[i].fr;i;i=b[i].se,y=b[i].fr)if(y!=fa[x]&&y!=son[x])dfs(y);
}
void Ins(int x,int v){
    for(int i=x;i<=n;i+=lb(i))t[i]+=v;
}
int Sum(int x){
    int tmp=0;
    for(int i=x;i>=1;i-=lb(i))tmp+=t[i];
    return tmp;
}
bool Que(int p,int q){
    while(top[p]!=top[q]){
        if(dfn[top[p]]if(Sum(dfn[p])-Sum(dfn[top[p]]-1))return 1;
        p=fa[top[p]];
    }
    if(dfn[p]return Sum(dfn[p])-Sum(dfn[q])?1:0;
}
int main(){
    n=rd(),m=rd();
    for(int i=1;i1),dfs(1);
//  for(int i=1;i<=n;i++)printf("%d ",dfn[i]);
//  printf("\n");
    for(int i=1;i<=m;i++){
        while((ch=getchar())!='C'&&ch!='Q'&&ch!='U');
        if(ch=='C'){
            p=rd(),q=rd();
            if(dfn[p]1);
        }
        else if(ch=='Q'){
            p=rd(),q=rd();
            Que(p,q)?puts("No"):puts("Yes");
        }
        else {
            p=rd();
            Ins(dfn[c[p]],-1);
        }
    }
}

你可能感兴趣的:(luogu,树链剖分,树上差分,树状数组)