BZOJ 4530 LCT/线段树合并

 

 

//By SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=200050;
int n,q,cnt,dfn[N],last[N],tree[N*16],lson[N*16],rson[N*16];
int first[N],next[N],v[N],w[N],tot,root[N],fa[N],deep[N],f[N];
struct Node{int xx,yy;char op[2];}node[N];
void dfs(int x){
    dfn[x]=++cnt;
    for(int i=first[x];~i;i=next[i])
        if(v[i]!=fa[x])deep[v[i]]=deep[x]+1,fa[v[i]]=x,dfs(v[i]);
    last[x]=cnt;
}
void add(int x,int y){v[tot]=y,next[tot]=first[x],first[x]=tot++;}
void Add(int x,int y){add(x,y),add(y,x);}
void insert(int l,int r,int &pos,int num,int wei){
    if(!pos)pos=++cnt;
    if(l==r){tree[pos]=wei;return;}
    int mid=(l+r)>>1;
    if(mid<num)insert(mid+1,r,rson[pos],num,wei);
    else insert(l,mid,lson[pos],num,wei);
    tree[pos]=tree[lson[pos]]+tree[rson[pos]];
}
int query(int l,int r,int pos,int L,int R){
    if(!pos)return 0;
    if(l>=L&&r<=R)return tree[pos];
    int mid=(l+r)>>1;
    if(mid<L)return query(mid+1,r,rson[pos],L,R);
    else if(mid>=R)return query(l,mid,lson[pos],L,R);
    else return query(l,mid,lson[pos],L,R)+query(mid+1,r,rson[pos],L,R);
}
void merge(int pos1,int &pos2){
    if(!pos2)pos2=++cnt;
    tree[pos2]+=tree[pos1];
//  printf("pos1=%d pos2=%d lson[pos1]=%d rson[pos1]=%d tree[pos]=%d\n",pos1,pos2,lson[pos1],rson[pos1],tree[pos2]);
    if(lson[pos1])merge(lson[pos1],lson[pos2]);
    if(rson[pos1])merge(rson[pos1],rson[pos2]);
}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void dfs2(int x){
    if(lson[x])dfs2(lson[x]);
    if(rson[x])dfs2(rson[x]);
}
int main(){
    memset(first,-1,sizeof(first));
    scanf("%d%d",&n,&q),getchar();
    for(int i=1;i<=q;i++){
        scanf("%s%d%d",node[i].op,&node[i].xx,&node[i].yy);
        if(node[i].op[0]=='A')Add(node[i].xx,node[i].yy);
    }
    for(int i=1;i<=n;i++)if(!fa[i])dfs(i);
    cnt=0;
    for(int i=1;i<=n;i++)insert(1,n,root[i],dfn[i],1),f[i]=i;
    for(int i=1;i<=q;i++){
        if(node[i].op[0]=='A'){
            int fx=find(node[i].xx),fy=find(node[i].yy);
            if(fx!=fy)merge(root[fx],root[fy]),f[fx]=fy;
        }
        else{
            if(deep[node[i].xx]>deep[node[i].yy])swap(node[i].xx,node[i].yy);
            int fy=find(node[i].yy);
            long long temp=query(1,n,root[fy],dfn[node[i].yy],last[node[i].yy]);
            printf("%lld\n",(tree[root[fy]]-temp)*temp);
        }
    }
}

 

//By SiriusRen
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=100050;
int n,m,xx,yy,fa[N],ch[N][2],rev[N],size[N],Size[N],q[N],top;
char op[10];
bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
void push_up(int x){size[x]=size[ch[x][0]]+size[ch[x][1]]+1+Size[x];}
void push_down(int x){if(rev[x])rev[ch[x][0]]^=1,rev[ch[x][1]]^=1,swap(ch[x][0],ch[x][1]),rev[x]=0;}
void rotate(int p){
    int q=fa[p],y=fa[q],x=(ch[q][1]==p);
    ch[q][x]=ch[p][!x],fa[ch[q][x]]=q;
    ch[p][!x]=q,fa[p]=y;
    if(!isroot(q)){
        if(ch[y][1]==q)ch[y][1]=p;
        if(ch[y][0]==q)ch[y][0]=p;
    }fa[q]=p,push_up(q);
}
void splay(int x){
    q[++top]=x;
    for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
    while(top)push_down(q[top]),top--;
    for(int y=fa[x];!isroot(x);rotate(x),y=fa[x])if(!isroot(y)){
        if((ch[fa[y]][0]==y)^(ch[y][0]==x))rotate(x);
        else rotate(y);
    }push_up(x);
}
void access(int x){for(int t=0;x;t=x,x=fa[x])splay(x),Size[x]+=size[ch[x][1]]-size[t],ch[x][1]=t,push_up(x);}
void makeroot(int x){access(x),splay(x),rev[x]^=1;}
void link(int x,int y){makeroot(x),makeroot(y),fa[x]=y,Size[y]+=size[x],push_up(y);}
void split(int x,int y){makeroot(x),access(y),splay(x);}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)size[i]=1;
    while(m--){
        scanf("%s%d%d",op,&xx,&yy);
        if(op[0]=='A')link(xx,yy);
        else split(xx,yy),printf("%lld\n",1ll*(Size[yy]+1)*(size[xx]-Size[yy]-1));
    }
}

 

转载于:https://www.cnblogs.com/SiriusRen/p/6789310.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值