BZOJ3091: 城市旅行

BZOJ3091: 城市旅行

https://lydsy.com/JudgeOnline/problem.php?id=3091

分析:

  • 沙雕\(lct\)题,维护一坨信息。
  • 其实也不是很多,维护答案,前缀和的和,后缀和的和,总和,\(siz\)
  • 注意翻转标记下传时要交换前缀后缀的信息。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <map>
#include <iostream>
using namespace std;
typedef long long ll;
#define N 50050
#define ls ch[p][0]
#define rs ch[p][1]
#define get(x) (ch[f[x]][1]==x)
#define isrt(x) (ch[f[x]][1]!=x&&ch[f[x]][0]!=x)
#define pii pair<int,int>
#define mp(x,y) make_pair(x,y)
#define db(x) cerr<<#x<<" = "<<x<<endl
int n,m,ch[N][2],f[N],rev[N];
map<pii,int>MP;
ll sum[N],lx[N],rx[N],tag[N],siz[N],val[N],s1[N],cc[N],ss[N],tot[N];
ll gcd(ll x,ll y) {return y?gcd(y,x%y):x;}
//s1=\sum\i     ss[n]=\sum\i*i     cc[n]=\sum\i*(n-i+1)
inline void pushup(int p) {
	siz[p]=siz[ls]+siz[rs]+1;
	tot[p]=tot[ls]+tot[rs]+val[p];
	lx[p]=lx[ls]+(tot[ls]+val[p])*(siz[rs]+1)+lx[rs];
	rx[p]=rx[rs]+(tot[rs]+val[p])*(siz[ls]+1)+rx[ls];
	sum[p]=sum[ls]+sum[rs]+val[p]*(siz[ls]+1)*(siz[rs]+1)+ rx[ls]*(siz[rs]+1) + lx[rs]*(siz[ls]+1);
}
inline void giv1(int p,ll d) {
	tag[p]+=d; val[p]+=d;
	tot[p]+=siz[p]*d;
	sum[p]+=d*cc[siz[p]];
	lx[p]+=d*s1[siz[p]];
	rx[p]+=d*s1[siz[p]];
}
inline void giv2(int p) {
	swap(lx[ls],rx[ls]);
	swap(lx[rs],rx[rs]);
	swap(ls,rs); 
	rev[p]^=1;
}
inline void pushdown(int p) {
	if(tag[p]) {
		if(ls) giv1(ls,tag[p]);
		if(rs) giv1(rs,tag[p]);
		tag[p]=0;
	}
	if(rev[p]) {
		if(ls) giv2(ls);
		if(rs) giv2(rs);
		rev[p]=0;
	}
}
void UPD(int p) {
	if(!isrt(p)) UPD(f[p]);
	pushdown(p);
}
void rotate(int x) {
	int y=f[x],z=f[y],k=get(x);
	if(!isrt(y)) ch[z][ch[z][1]==y]=x;
	ch[y][k]=ch[x][!k]; f[ch[y][k]]=y;
	ch[x][!k]=y; f[y]=x; f[x]=z;
	pushup(y); pushup(x);
}
void splay(int x) {
	UPD(x);
	for(int d;d=f[x],!isrt(x);rotate(x)) 
		if(!isrt(d)) rotate(get(x)==get(d)?d:x);
}
void access(int p) {
	int t=0;
	while(p) {
		splay(p);
		rs=t; t=p; pushup(p); p=f[p];
	}
}
void makeroot(int p) {
	access(p); splay(p); giv2(p);
}
void link(int x,int p) {
	makeroot(x); splay(x); f[x]=p;
}
void cut(int x,int p) {
	makeroot(x); access(p); splay(p); ls=f[x]=0;
}
int find(int p) {
	access(p); splay(p); while(ls) pushdown(p),p=ls; splay(p); return p;
}
int main() {
	// freopen("ink.in","r",stdin);
	// freopen("ink.out","w",stdout);
	scanf("%d%d",&n,&m);
	int i,x,y;
	for(i=1;i<=n;i++) s1[i]=ll(i)*(i+1)/2;
	for(i=1;i<=n;i++) ss[i]=ss[i-1]+ll(i)*i;
	for(i=1;i<=n;i++) cc[i]=(i+1)*s1[i]-ss[i];
	for(i=1;i<=n;i++) scanf("%lld",&val[i]),pushup(i);
	for(i=1;i<n;i++) {
		scanf("%d%d",&x,&y);
		link(x,y);
		if(x>y) swap(x,y);
		MP[mp(x,y)]=1;
	}
	int opt;
	while(m--) {
		scanf("%d%d%d",&opt,&x,&y);
		if(x>y) swap(x,y);
		if(opt==1) {
			if(!MP.count(mp(x,y))||!MP[mp(x,y)]) continue;
			cut(x,y); MP[mp(x,y)]=0;
		}else if(opt==2) {
			if(find(x)==find(y)) continue;
			link(x,y); MP[mp(x,y)]=1;
		}else if(opt==3) {
			int d;
			scanf("%d",&d);
			if(find(x)!=find(y)) continue;
			makeroot(x); access(y); splay(y);
			giv1(y,d);
		}else {
			if(find(x)!=find(y)) {
				puts("-1"); continue;
			}
			makeroot(x); access(y); splay(y);
			ll re=sum[y], s=siz[y]*(siz[y]+1)/2;
			ll cd=gcd(re,s);
			re/=cd, s/=cd;
			printf("%lld/%lld\n",re,s);
		}
	}
}
/*
4 5 
1 3 2 5
1 2
1 3
2 4
4 2 4
1 2 4
2 3 4
3 1 4 1
4 1 4
*/
posted @ 2018-12-09 18:49  fcwww  阅读(195)  评论(0编辑  收藏  举报