loj 558 我们的 CPU 遭到攻击

这题很明显是lct,我们只要可以维护黑色点深度和即可。

但是lct维护子树信息好难写啊。
首先边权比较难处理,所以偷懒加虚点表示边。

然后考虑维护子树距离和,需要维护splay上的边权和。
为了可以reverse,还必须维护一个反的距离和。
虚子树的答案更新在access和link连虚边的时候。
好烦啊。

千万不要把splay之前的下传标记写挂,记得只下传本splay的标记。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=200005;

struct node{
	int blcnt;//black cnt
	int non_cnt;//xzs
	ll non_dis;
	ll sumval;//bian quan he
	int val;//bian quan
	ll disl,disr;//disl disr
	bool fl,bl;
	int fa,ch[2];
	void clear(){
		memset(this,0,sizeof(*this));
	}
	void print(){
		cout<<"blcnt: "<<blcnt<<endl;
		cout<<"non_cnt: "<<non_cnt<<endl;
		cout<<"non_dis: "<<non_dis<<endl;
		cout<<"sumval: "<<sumval<<endl;
		cout<<"val: "<<val<<endl;
		cout<<"dislr: "<<disl<<" "<<disr<<endl;
		cout<<"flip: "<<fl<<endl;
		cout<<"bl:"<<bl<<endl;
		cout<<"fa:"<<fa<<endl;
		cout<<"ch[0:1]:"<<ch[0]<<" "<<ch[1]<<endl;
	}
}T[N];

int n,m,k;
bool get(int x){
	return T[T[x].fa].ch[1]==x;
}
bool nroot(int x){
	return T[T[x].fa].ch[0]==x||T[T[x].fa].ch[1]==x;
}
bool ISBLACK(int x){
	return x<=n&&T[x].bl;
}
void pushup(int x){
	//cerr<<"pushup"<<x<<endl;
	int ls=T[x].ch[0],rs=T[x].ch[1];
	T[x].blcnt=T[x].bl+T[ls].blcnt+T[rs].blcnt+T[x].non_cnt;
	T[x].sumval=T[x].val+T[ls].sumval+T[rs].sumval;
	
	T[x].disl=T[x].disr=T[x].non_dis;

	T[x].disl+=T[ls].disl+T[rs].disl+(ISBLACK(x)+T[x].non_cnt+T[rs].blcnt)*(T[ls].sumval+T[x].val);
	T[x].disr+=T[rs].disr+T[ls].disr+(ISBLACK(x)+T[x].non_cnt+T[ls].blcnt)*(T[rs].sumval+T[x].val);
};

void puttag(int x){
	swap(T[x].disl,T[x].disr);
	swap(T[x].ch[0],T[x].ch[1]);
	T[x].fl^=1;
}

void pushdown(int x){
	if (T[x].fl){
		if (T[x].ch[0]) puttag(T[x].ch[0]);
		if (T[x].ch[1]) puttag(T[x].ch[1]);
		T[x].fl=0;
	}
}
void allpushdown(int x){
	if (nroot(x)) allpushdown(T[x].fa);
	pushdown(x);
}


void rotate(int x){
	//cerr<<"roate"<<x<<endl;
	int f=T[x].fa,gx=get(x),xs=T[x].ch[gx^1];
	T[x].fa=T[f].fa; if (nroot(f)) T[T[f].fa].ch[get(f)]=x;
	T[f].fa=x; T[x].ch[gx^1]=f;
	if (xs) T[xs].fa=f; T[f].ch[gx]=xs;
	pushup(f);
	//cerr<<"faf"<<T[1].fa<<" "<<T[2].ch[0]<<" "<<T[2].ch[1]<<endl;
}

void splay(int x){
	//cerr<<"splay"<<x<<endl;
	allpushdown(x);
	for (; nroot(x); rotate(x)){
		int f=T[x].fa;
		if (nroot(f)&&get(f)==get(x)) rotate(f);
	}
	pushup(x);
	//cerr<<"splayend"<<endl;
}

void access(int x){//????
	//cerr<<"access"<<x<<" "<<"fa"<<T[x].fa<<" "<<T[3].fa<<endl;
	int la=0;
	while (1){
		splay(x);
		T[x].non_cnt+=T[T[x].ch[1]].blcnt-T[la].blcnt;
		T[x].non_dis+=T[T[x].ch[1]].disl-T[la].disl;
		T[x].ch[1]=la;
		pushup(x);
		la=x;
		if (!(x=T[x].fa)) break;	
	}
}

void makeroot(int x){
	//cerr<<"makeroot"<<x<<" "<<T[x].fa<<" "<<T[T[x].fa].fa<<" "<<T[T[T[x].fa].fa].fa<<endl;
	access(x);
	//cerr<<"ACCEND"<<endl;
	splay(x);
	//cerr<<"ASM"<<T[1].fa<<" "<<T[2].fa<<" "<<T[3].fa<<" "<<T[3].ch[0]<<endl;
	puttag(x);
	//cerr<<":MEDN"<<endl;
}

void __link(int x,int y){
	//link virtual edge
	//cerr<<"__link"<<x<<" "<<y<<endl;
	makeroot(x);
	makeroot(y);
	//cerr<<"YYB"<<T[y].ch[0]<<endl;
	T[y].fa=x;
	T[x].non_cnt+=T[y].blcnt;
	T[x].non_dis+=T[y].disl;
	pushup(x);
	//cerr<<"ASF__link"<<T[1].fa<<" "<<T[2].fa<<" "<<T[3].fa<<endl;
}
stack<int> s;
map<int,int> mp[N>>1];
void link(int u,int v,int w){
	//cerr<<"link"<<u<<" "<<v<<" "<<w<<endl;
	int cnt=s.top(); s.pop();
	mp[u][v]=mp[v][u]=cnt;
	T[cnt].clear();
	T[cnt].val=w;
	__link(u,cnt);
	__link(v,cnt);
}

void __cut(int x,int y){
	makeroot(x);
	access(y);
	splay(y);
	assert(T[y].ch[0]==x);
	T[y].ch[0]=0;
	T[x].fa=0;
	pushup(y);
}

void cut(int u,int v){
	int cnt=mp[u][v];
	__cut(u,cnt);
	__cut(v,cnt);
	s.push(cnt);
}

void flip(int u){
	makeroot(u);
	T[u].bl^=1;
	pushup(u);
}

void Dfs(int x){
	//cerr<<"Indfs"<<x<<" "<<T[x].fl<<" "<<T[x].ch[0]<<" "<<T[x].ch[1]<<" "<<T[x].sumval<<" "<<T[x].disl<<" "<<T[x].blcnt<<endl;
	if (T[x].ch[0]) Dfs(T[x].ch[0]);
	if (T[x].ch[1]) Dfs(T[x].ch[1]);
}

ll query(int u){
	//cerr<<"query"<<u<<endl;
	makeroot(u);
	//Dfs(u);
	//cerr<<"U"<<u<<endl;
	//cerr<<"query"<<T[u].blcnt<<endl;
	//cerr<<"query"<<T[u].non_dis<<" "<<T[u].non_cnt<<" "<<T[u].ch[0]<<" "<<T[u].ch[1]<<endl;
	//cerr<<"Trifa"<<T[3].fa<<" "<<T[3].val<<endl;
	//cerr<<"query"<<T[u].sumval<<endl;
	return T[u].disl;
}

int main(){
	scanf("%d%d%d",&n,&m,&k);
	for (int i=n+n-1; i>n; --i) s.push(i);
	for (int i=1; i<=m; ++i){
		//cerr<<"DOD"<<i<<endl;
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		//cerr<<u<<" "<<v<<" "<<w<<endl;
		link(u,v,w);
	}
	/*for (int i=1; i<=n+n-1; ++i){
		cerr<<"I"<<i<<endl;
		T[i].print();
		}*/
	//return 0;
	for (int i=1; i<=k; ++i){
		//cerr<<"action:------------------"<<i<<endl;
		char s[10];
		int u,v,w;
		scanf("%s%d",s,&u);
		//cerr<<u<<endl;
		if (s[0]=='C'||s[0]=='L') scanf("%d",&v);
		if (s[0]=='L') scanf("%d",&w);
		switch (s[0]){
		case 'L':
			link(u,v,w);
			break;
		case 'C':
			cut(u,v);
			break;
		case 'F':
			flip(u);
			break;
		case 'Q':
			cout<<query(u)<<'\n';
			break;
		}

		//cerr<<"DODODODDD"<<endl;
		//cerr<<"!!!!!!!"<<endl;
		//for (int i=1; i<n+n; ++i) T[i].print();
		
		//cerr<<"afterall"<<T[1].fa<<" "<<T[2].fa<<" "<<T[3].fa<<endl;
	}
}

差点就是最长代码了,足以看出调试的艰辛。

posted @ 2019-03-19 19:23  Yuhuger  阅读(365)  评论(0)    收藏  举报