Gty的超级妹子树,洛谷P2166,树上分块+主席树(坑)

正题

      其实这题,就跟Gty的妹子树是差不多的。就是多了一个删边操作。

      我们还是选择了分块+主席树,但是问题就是怎么断边。

      首先我们可以知道如果这条边是块与块之间的连接边,那么直接断就可以了。

      如果不是,那么我们要继续往下搜索,把那些原先在块内的节点都删掉,然后在新开一个块存储断边后u所在的块,那么这时候u肯定是块顶。

      然后让那些子树内原先连着u所在块的块,认u的所在块为块父亲即可。

      那么我们往下遍历的依据就是我是你的父亲(块遍历时是我是你的块父亲)即可。

      最后完成操作。

      时间复杂度n*log(n)~n*sqrt(n)*log(n)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define INF 2147483647
using namespace std;

int n;
int sqrtn;
int ls[26000010],rs[26000010];
int tot[26000010];
int f[200010];
int root[200010];
struct edge{
    int y,next;
}s[400010];
edge news[1200010];
int id[200010];
int first[200010];
int fir[200010];
int d[200010];
int fa[200010];
bool top[200010];
int m,tt=0,op,sum[200010],ll=0,len=0;
long long v;

void ins(int x,int y){
    len++;
    s[len].y=y;s[len].next=first[x];first[x]=len;
}

void inss(int x,int y){
    ll++;
    news[ll].y=y;news[ll].next=fir[x];fir[x]=ll;
}

inline char nc() {
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}

#define getchar() nc()

void read(int &to){
    to=0;
    char ch=getchar();
    int f=1;
    while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0' && ch<='9') to=to*10+ch-'0',ch=getchar();
    to*=f;
}

void update(int &now,long long l,long long r){
    if(now==0) now=++tt;
    tot[now]+=op;
    if(l==r) return ;
    long long mid=(l+r)/2;
    if(v<=mid) update(ls[now],l,mid);
    else update(rs[now],mid+1,r);
}

int num=0;

void dfs(int x){
    if(sum[id[f[x]]]==sqrtn) {//新遍历 
    	sum[id[x]=++num]=1;
        inss(id[f[x]],id[x]);
        fa[id[x]]=id[f[x]];
        top[x]=true;
    }
    else sum[id[x]=id[f[x]]]++;
    v=d[x];op=1;
    update(root[id[x]],0,INF);
    for(int i=first[x];i!=0;i=s[i].next){
        int y=s[i].y;
        if(y!=f[x]){
            f[y]=x;
            dfs(y);
        }
    }
}

int ans=0;

void findal(int x,int tar){
    for(int i=fir[x];i!=0;i=news[i].next)
        if(fa[news[i].y]==x) findal(news[i].y,tar);
    long long l=0,r=INF;
    int now=root[x];
    if(tar<0){
    	ans+=tot[now];
        return ;
    }
    while(l<r){
        long long mid=(l+r)/2;
        if(tar<=mid) {
            ans+=tot[rs[now]];
            now=ls[now];
            r=mid;
        }
        else{
            now=rs[now];
            l=mid+1;
        }
    }
}

void findso(int now,int y){
    if(d[now]>y) ans++;
    for(int i=first[now];i!=0;i=s[i].next)
        if(f[s[i].y]==now){
        	if(id[s[i].y]==id[now]) findso(s[i].y,y);
            else findal(id[s[i].y],y);
        }
}

int get_kth(int x,int y){
    ans=0;
    findso(x,y);
    return ans;
}

void change(int x,int y){
    v=d[x];op=-1;
    update(root[id[x]],0,INF);
    v=d[x]=y;op=1;
    update(root[id[x]],0,INF);
}

void add(int x,int y){
    n++;
    d[n]=y;
    f[n]=x;
    ins(x,n);
    dfs(n);
}

int last;

void findnext(int x){
	v=d[x];op=-1;
	update(root[id[x]],0,INF);
	v=d[x];op=1;
	update(root[id[x]=num],0,INF);
	for(int i=first[x];i!=0;i=s[i].next)
		if(f[s[i].y]==x){
			if(id[s[i].y]==last) findnext(s[i].y); 
			else {
				fa[id[s[i].y]]=num;
				inss(num,id[s[i].y]);
			}
		}
}

void del(int x){
	last=id[x];
	if(!top[x]){
		++num;
		findnext(x);
	}
	f[x]=0;fa[num]=0;
	top[x]=true;
}

int main(){
    read(n);
    for(int i=1;i<=n-1;i++){
        int x,y;
        read(x);read(y);
        ins(x,y);ins(y,x);
    }
    for(int i=1;i<=n;i++)
        read(d[i]);
    read(m);
    sqrtn=sqrt(n)*log2(n)*2;
    dfs(1);
    int type;
    int x,y;
    int lastans=0;
    while(m--){
        read(type);read(x);
		if(type!=3) read(y);
		x^=lastans;y^=lastans;
        if(type==0){
            lastans=get_kth(x,y);
            printf("%d\n",lastans);
        }
        else if(type==1) change(x,y);
        else if(type==2) add(x,y);
        else if(type==3) del(x);
    }
}

洛谷的T人水准不是一般的

猜你喜欢

转载自blog.csdn.net/Deep_Kevin/article/details/80981875