1. 程式人生 > >bzoj4811: [Ynoi2017]由乃的OJ 樹鏈剖分+線段樹 拆位

bzoj4811: [Ynoi2017]由乃的OJ 樹鏈剖分+線段樹 拆位

bzoj4811: [Ynoi2017]由乃的OJ

Description

由乃正在做她的OJ。現在她在處理OJ上的使用者排名問題。OJ上註冊了n個使用者,編號為1~",一開始他們按照編號
排名。由乃會按照心情對這些使用者做以下四種操作,修改使用者的排名和編號:然而由乃心情非常不好,因為Deus天
天問她題。。。因為Deus天天問由乃OI題,所以由乃去學習了一下OI,由於由乃智商挺高,所以OI學的特別熟練她
在RBOI2016中以第一名的成績進入省隊,參加了NOI2016獲得了金牌保送
Deus:這個題怎麼做呀?
yuno:這個不是NOI2014的水題嗎。。。
Deus:那如果出到樹上,多組鏈詢問,帶修改呢?
yuno:誒。。。???
Deus:這題叫做睡覺困難綜合徵喲~
雖然由乃OI很好,但是她基本上不會DS,線段樹都只會口胡,比如她NOI2016的分數就是100+100+100+0+100+100。
。。NOIP2017的分數是100+0+100+100+0+100所以她還是隻能找你幫她做了。。。
給你一個有n個點的樹,每個點的包括一個位運算opt和一個權值x,位運算有&,l,^三種,分別用1,2,3表示。
每次詢問包含三個數x,y,z,初始選定一個數v。然後v依次經過從x到y的所有節點,每經過一個點i,v就變成v opti
xi,所以他想問你,最後到y時,希望得到的值儘可能大,求最大值?給定的初始值v必須是在[0,z]之間。每次修
改包含三個數x,y,z,意思是把x點的操作修改為y,數值改為z

Input

第一行三個數n,m,k。k的意義是每個點上的數,以及詢問中的數值z都 <2^k。之後n行
每行兩個數x,y表示該點的位運算編號以及數值
之後n - 1行,每行兩個數x,y表示x和y之間有邊相連
之後m行,每行四個數,Q,x,y,z表示這次操作為Q(1位詢問,2為修改),x,y,z意義如題所述
0 <= n , m <= 100000 , k <= 64

Output

對於每個操作1,輸出到最後可以造成的最大刺激度v

Sample Input

5 5 3
1 7
2 6
3 7
3 6
3 1
1 2
2 3
3 4
1 5
1 1 4 7
1 1 3 5
2 1 1 3
2 3 3 3
1 1 3 2

Sample Output

7
1
5

分析

題目原型是 [Noi2014]起床困難綜合症
這題把他搬到了樹上,加上了修改。
實際上沒差,還是一樣的做法,只不過線段樹中的每個節點代表的是從某一個方向帶入 0 0 1111

1111\cdots 進入區間運算後的結果。
然後上樹剖就 O ( n l o g 2 n ) O(nlog^2n)

程式碼

巨難調,要注意方向。
zkw真好玩。

#include<bits/stdc++.h>
#define pa std::pair<ULL, ULL>
#define f0 first
#define f1 second
#define mp std::make_pair
typedef unsigned long long ULL;
const int N = 1e5 + 10, Nt = 131072; const ULL ALL = -1;
ULL ri() {
	char c = getchar(); ULL x = 0; for(;c < '0' || c > '9'; c = getchar()) ;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x;
}
int sz[N], ds[N], in[N], d[N], de[N], pr[N], fa[N], nx[N << 1], to[N << 1];
int st1[N], st2[N], ps[N], opt[N], tp, tot, K; pa st[N]; ULL val[N], bin[64];
void add(int u, int v) {to[++tp] = v; nx[tp] = pr[u]; pr[u] = tp;}
void adds(int u, int v) {add(u, v); add(v, u);}
ULL Cal(int o, ULL v, ULL st) {return o == 1 ? v & st : (o == 2 ? v | st : v ^ st);}
struct D {pa f[2];void Ini(int o, ULL v) {f[0] = f[1] = mp(Cal(o, v, 0), Cal(o, v, ALL));}}T[Nt << 1];
pa operator+(pa a, pa b) {
	pa r;
	r.f0 = (a.f0&b.f1)|(~a.f0&b.f0);
	r.f1 = (a.f1&b.f1)|(~a.f1&b.f0);
	return r;
}
D operator+(D a, D b) {
	D r;
	r.f[0] = a.f[0] + b.f[0];
	r.f[1] = b.f[1] + a.f[1];
	return r;
}
void Up(int i, int o, ULL v) {for(T[i += Nt].Ini(o, v); i >>= 1; T[i] = T[i << 1] + T[i << 1 | 1]);}
pa Que(int s, int t, bool p) {
	int tp1 = 0, tp2 = 0;
	for(s += Nt - 1, t += Nt + 1;s ^ t ^ 1; s >>= 1, t >>= 1) {
		if(~s & 1) st1[++tp1] = s ^ 1;
		if(t & 1) st2[++tp2] = t ^ 1;
	}
	for(;tp2;) st1[++tp1] = st2[tp2--];
	pa r; int i = 2;
	if(p) for(r = T[st1[tp1]].f[p];--tp1;) r = r + T[st1[tp1]].f[p];
	else for(r = T[st1[1]].f[p];i <= tp1; ++i) r = r + T[st1[i]].f[p]; 
	return r;
}
void dfs1(int u, int ff) {
	sz[u] = 1; fa[u] = ff; de[u] = de[ff] + 1;
	for(int i = pr[u]; i; i = nx[i])
		if(to[i] != ff) {
			dfs1(to[i], u), sz[u] += sz[to[i]];
			sz[ds[u]] < sz[to[i]] ? ds[u] = to[i] : 0;
		}
}
void dfs2(int u, int c) {
	d[u] = c; in[u] = ++tot; ps[tot] = u; 
	if(!ds[u]) return ; dfs2(ds[u], c);
	for(int i = pr[u]; i; i = nx[i])
		if(to[i] != fa[u] && to[i] != ds[u]) 
			dfs2(to[i], to[i]);
}
int Lca(int u, int v) {
	for(;d[u] != d[v]; u = fa[d[u]]) if(de[d[u]] < de[d[v]]) u ^= v ^= u ^= v;
	return de[u] < de[v] ? u : v;
}
pa Link(int u, int c, bool p) {
	int x = de[c] + p, tp = 0; 
	for(;de[d[u]] >= x; u = fa[d[u]]) st[++tp] = Que(in[d[u]], in[u], p);
	if(de[u] >= x) st[++tp] = Que(in[u] - de[u] + x, in[u], p);
	pa r; int i = 2;
	if(!p) for(r = st[tp];--tp;) r = r + st[tp];
	else for(r = st[1];i <= tp; ++i) r = r + st[i];
	return r;
}
ULL Solve(int u, int v, ULL M) {
	int c = Lca(u, v); ULL ans = 0; pa r;
	r = Link(v, c, 0); if(u != c) r = Link(u, c, 1) + r;
	for(int i = K - 1; ~i; --i) {
		bool c0 = r.f0 & bin[i], c1 = r.f1 & bin[i];
		if(c0 >= c1 || bin[i] > M) ans |= c0 ? bin[i] : 0;
		else ans |= c1 ? bin[i] : 0, M -= bin[i];
	}
	return ans;
}
int main() {
	int n = ri(), m = ri(); K = ri();
	bin[0] = 1; for(int i = 1;i < K; ++i) bin[i] = bin[i - 1] << 1;
	for(int i = 1;i <= n; ++i) opt[i] = ri(), val[i] = ri();
	for(int i = 1;i < n; ++i) adds(ri(), ri());
	dfs1(1, 0); dfs2(1, 1); 
	for(int i = 1;i <= n; ++i) T[i + Nt].Ini(opt[ps[i]], val[ps[i]]);
	for(int i = Nt - 1;i; --i) T[i] = T[i << 1] + T[i << 1 | 1];
	for(;m--;) {
		int op = ri(), x = ri(), y = ri(); ULL z = ri();
		if(op == 1) printf("%llu\n", Solve(x, y, z));
		else Up(in[x], y, z);
	}
	return 0;
}