bzoj3514【lct】【可持久化线段树】

lct + 主席树


(这个ntr数组  吼啊  有道(zhe)理  污拉拉。。

姑且就叫ntr算法咯。。



#include <cstdio>
#include <iostream>
#include <algorithm>

using namespace std;

int n,m,k,ty;

int ch[400010][2],fa[400010],rv[400010],x[400010],mi[400010];
int st[400010],tp;

struct data {
	int x,ord;
	bool operator < (const data &b)const {
		return x < b.x;
	}
}ntr[200010];

struct edge {
	int u,v;
}e[200010];
int head[200010];

struct seg {
	int ls,rs,l,r,sum;
}tr[4400010];
int cnt;
int rt[200010],last;

int read_int () {
	char c = getchar();
	int re = 0;
	for(;c > '9' || c < '0';c = getchar());
	for(;c >= '0' && c <= '9';c = getchar())
		re = re * 10 + c - '0';
	return re;
}

int find (int u) {
	if(u == head[u])
		return u;
	return head[u] = find(head[u]);
}

void pu (int u) {
	mi[u] = x[u];
	mi[u] = min(mi[u],mi[ch[u][1]]);
	mi[u] = min(mi[u],mi[ch[u][0]]);
}

void reverse (int u) {
	int t = ch[u][0];
	ch[u][0] = ch[u][1];
	ch[u][1] = t;
	rv[u] ^= 1;
}

void pd (int u) {
	if(!rv[u])
		return;
	rv[u] = 0;
	reverse(ch[u][0]);
	reverse(ch[u][1]);
}

void rot (int u,int d) {
	ch[fa[u]][d ^ 1] = ch[u][d];
	if(ch[u][d])
		fa[ch[u][d]] = fa[u];
	int t = fa[fa[u]];
	fa[fa[u]] = u;
	ch[u][d] = fa[u];
	fa[u] = t;
	
	pu(ch[u][d]);
	pu(u);
	
	if(!t)
		return;
	if(ch[t][0] == ch[u][d])
		ch[t][0] = u;
	if(ch[t][1] == ch[u][d])
		ch[t][1] = u;
}

void splay (int u) {
	st[tp = 1] = u;
	int t = u;
	while(ch[fa[t]][0] == t || ch[fa[t]][1] == t) {
		t = fa[t];
		st[++tp] = t;
	}
	while(tp)
		pd(st[tp--]);
	
	while(ch[fa[u]][0] == u || ch[fa[u]][1] == u) {
		if(ch[fa[fa[u]]][0] != fa[u] && ch[fa[fa[u]]][1] != fa[u]) {
			if(ch[fa[u]][0] == u)
				rot(u,1);
			else rot(u,0);
		}
		else {
			int d = ch[fa[fa[u]]][0] == fa[u];
			if(ch[fa[u]][d] == u) {
				rot(u,d ^ 1);
				rot(u,d);
			}
			else {
				rot(u,d);
				rot(u,d);
			}
		}
	}
}

void access (int u) {
	int v = 0;
	while(u) {
		splay(u);
		ch[u][1] = v;
		pu(u);
		v = u;
		u = fa[u];
	}
}

void mtr (int u) {
	access(u);
	splay(u);
	reverse(u);
}

void link (int u,int v) {
	mtr(u);
	mtr(v);
	fa[u] = v;
}

void cut (int u,int v) {
	mtr(v);
	access(v);
	splay(u);
	fa[u] = 0;
}

void push_up (int M) {
	tr[M].sum = tr[tr[M].ls].sum + tr[tr[M].rs].sum;
}

void build_ori (int l,int r,int M) {
	tr[M].l = l;
	tr[M].r = r;
	if(l == r)
		return;
	int mid = (l + r) / 2;
	tr[M].ls = ++cnt;
	build_ori(l,mid,tr[M].ls);
	tr[M].rs = ++cnt;
	build_ori(mid + 1,r,tr[M].rs);
}

void build (int last,int ord,int M) {
	tr[M].l = tr[last].l;
	tr[M].r = tr[last].r;
	if(tr[M].l == tr[M].r) {
		tr[M].sum = 1;
		return;
	}
	
	int mid = (tr[M].r + tr[M].l) / 2;
	if(ord > mid) {
		tr[M].ls = tr[last].ls;
		tr[M].rs = ++cnt;
		build(tr[last].rs,ord,tr[M].rs);
	}
	else {
		tr[M].rs = tr[last].rs;
		tr[M].ls = ++cnt;
		build(tr[last].ls,ord,tr[M].ls);
	}
	push_up(M);
}

int find_ans (int l,int r,int M) {
	if(l == tr[M].l && tr[M].r == r)
		return tr[M].sum;
	int mid = (tr[M].l + tr[M].r) / 2;
	if(l > mid)
		return find_ans(l,r,tr[M].rs);
	else {
		if(r <= mid)
			return find_ans(l,r,tr[M].ls);
		else return find_ans(l,mid,tr[M].ls) + find_ans(mid + 1,r,tr[M].rs);
	}
}

int main () {
	n = read_int();
	m = read_int();
	k = read_int();
	ty = read_int();
	
	for(int i = 0;i <= n;++i) {
		x[i] = mi[i] = 0x3f3f3f3f;
		head[i] = i;
	}
	
	for(int i = 1;i <= m;++i) {
		ntr[i].ord = i;
		e[i].u = read_int();
		e[i].v = read_int();
		if(e[i].u == e[i].v) {
			ntr[i].x = i;
			continue;
		}
		if(find(e[i].u) == find(e[i].v)) {
			mtr(e[i].u);
			access(e[i].v);
			splay(e[i].u);
			ntr[i].x = mi[e[i].u];
			cut(e[ntr[i].x].u,ntr[i].x + n);
			cut(e[ntr[i].x].v,ntr[i].x + n);
		}
		else head[find(e[i].u)] = find(e[i].v);
		x[n + i] = mi[n + i] = i;
		link(n + i,e[i].u);
		link(n + i,e[i].v);
	}
	
	sort(ntr + 1,ntr + 1 + m);
	
	rt[0] = last = cnt = 1;
	
	build_ori(1,m,1);
	
	for(int i = 1;i <= m;++i) {
		if(ntr[i].x != ntr[i - 1].x) {
			for(int j = ntr[i - 1].x + 1;j < ntr[i].x;++j)
				rt[j] = last;
		}
		build(last,ntr[i].ord,rt[ntr[i].x] = ++cnt);
		last = rt[ntr[i].x];
	}
	
	for(int i = ntr[m].x + 1;i <= m;++i) {
		rt[i] = last;
	}
	
	int L,R,ans = 0;
	
	for(int i = 1;i <= k;++i) {
		L = read_int();
		R = read_int();
		if(ty) {
			L ^= ans;
			R ^= ans;
		}
		ans = n - find_ans(L,R,rt[L - 1]);
		printf("%d\n",ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值