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]起床困難綜合症
這題把他搬到了樹上,加上了修改。
實際上沒差,還是一樣的做法,只不過線段樹中的每個節點代表的是從某一個方向帶入
或
進入區間運算後的結果。
然後上樹剖就
了
程式碼
巨難調,要注意方向。
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;
}