您的位置:首页 > 其它

4811: [Ynoi2017]由乃的OJ

2017-05-03 14:55 295 查看

4811: [Ynoi2017]由乃的OJ

Time Limit: 6 Sec  Memory Limit: 256 MB
Submit: 188  Solved: 70

[Submit][Status][Discuss]

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

HINT

Source

By 佚名提供

[Submit][Status][Discuss]


在查询答案的时候,不妨从高到低逐位处理

每次枚举这一位填0还是1(要能填),然后查询这一位填这个数字对答案的贡献

如果填0的贡献大于等于填1的贡献,那么这一位肯定填0

否则贪心地想,这一位填1肯定也是最优的

那么需要支持快速修改和查询一个数字在树上走了一段路后的答案

先对这棵树进行树链剖分操作

每次询问,等于是在线段树上走log个区间(一整段重链单独提出来作一个区间)

那么维护一个二元组(x,y)其中x,y为两个二进制数码,x的第i位表示第i位填0的返回值,y类似

这样合并用位运算就能做到O(1)

剩下都是数据结构的问题了。。。。#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
//#include<ctime>
using namespace std;

const int T = 4;
const int M = 17;
const int N = 64;
const int maxn = 1E5 + 10;
typedef unsigned long long u64;

int n,m,k,tot,dfs_clock,tp,siz[maxn],Nex[maxn],dfn[maxn],pos[maxn],DP[maxn]
,fa[maxn][M],bel[maxn],len[maxn],ft[maxn],lt[maxn],typ[maxn],Name[maxn];
u64 Max,A[maxn],mi
; bool Huge[maxn];

struct data{
u64 v0,v1;
data operator + (const data &B)
{
data c;
c.v0 = (v0 & B.v1) | (~v0 & B.v0);
c.v1 = (v1 & B.v1) | (~v1 & B.v0);
return c;
}
}Left[maxn*T],Right[maxn*T],L[maxn],R[maxn],stk[maxn],s2[maxn],Val[maxn];

vector <int> v[maxn];

inline u64 Opt(u64 x,u64 y,int com)
{
return com == 1 ? x & y : (com == 2 ? x | y : x ^ y);
}

inline u64 Read()
{
char ch = getchar(); u64 ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret * (u64)(10) + (u64)(ch - '0'),ch = getchar();
return ret;
}

char s[22];
inline void Print(u64 x)
{
if (!x) {puts("0"); return;} int len = 0;
while (x) s[++len] = x % (u64)(10),x /= (u64)(10);
for (int i = len; i; i--) putchar(s[i] + '0'); puts("");
}

inline int Quickfa(int x,int y)
{
for (int now = 0; y; y >>= 1,now++)
if (y & 1) x = fa[x][now];
return x;
}

inline int LCA(int p,int q)
{
if (DP[p] < DP[q]) swap(p,q);
for (int i = M - 1; i >= 0; i--)
if (DP[p] - (1 << i) >= DP[q]) p = fa[p][i];
if (p == q) return p;
for (int i = M - 1; i >= 0; i--)
if (fa[p][i] != fa[q][i]) p = fa[p][i],q = fa[q][i];
return fa[p][0];
}

inline void Dfs1(int x,int from)
{
int Max = 0; siz[x] = 1;
for (int i = 1; i < M; i++) fa[x][i] = fa[fa[x][i-1]][i-1];
for (int i = 0; i < v[x].size(); i++)
{
int to = v[x][i]; if (to == from) continue;
fa[to][0] = x; DP[to] = DP[x] + 1; Dfs1(to,x);
siz[x] += siz[to]; if (siz[to] > Max) Max = siz[to],Nex[x] = to;
}
}

inline void Dfs2(int x,int from)
{
dfn[x] = ++dfs_clock; Name[dfs_clock] = x;
if (Nex[x])
{
int to = Nex[x]; Huge[to] = 1;
if (Huge[x]) bel[to] = bel[x],pos[to] = pos[x] + 1;
else pos[to] = 1,bel[to] = ++tot,ft[bel[to]] = dfs_clock + 1;
Dfs2(to,x);
}
else if (Huge[x]) lt[bel[x]] = dfn[x],len[bel[x]] = pos[x];
for (int i = 0; i < v[x].size(); i++)
{
int to = v[x][i];
if (to == from || to == Nex[x]) continue;
Dfs2(to,x);
}
}

inline void Build(int o,int l,int r)
{
if (l == r)
{
Left[o] = Right[o] = Val[Name[l]]; return;
}
int mid = l + r >> 1;
Build(o<<1,l,mid); Build(o<<1|1,mid+1,r);
Left[o] = Left[o<<1] + Left[o<<1|1];
Right[o] = Right[o<<1|1] + Right[o<<1];
}

inline void Search_Left(int o,int l,int r,int ql,int qr)
{
if (ql <= l && r <= qr)
{
stk[++tp] = Left[o]; return;
}
int mid = l + r >> 1;
if (ql <= mid) Search_Left(o<<1,l,mid,ql,qr);
if (qr > mid) Search_Left(o<<1|1,mid+1,r,ql,qr);
}

inline void Search_Right(int o,int l,int r,int ql,int qr)
{
if (ql <= l && r <= qr)
{
stk[++tp] = Right[o]; return;
}
int mid = l + r >> 1;
if (ql <= mid) Search_Right(o<<1,l,mid,ql,qr);
if (qr > mid) Search_Right(o<<1|1,mid+1,r,ql,qr);
}

inline data Query_Left(int l,int r)
{
tp = 0; Search_Left(1,1,n,l,r);
data ret; ret.v0 = 0; ret.v1 = Max;
for (int i = 1; i <= tp; i++) ret = ret + stk[i]; return ret;
}

inline data Query_Right(int l,int r)
{
tp = 0; Search_Right(1,1,n,l,r);
data ret; ret.v0 = 0; ret.v1 = Max;
for (int i = tp; i > 0; i--) ret = ret + stk[i]; return ret;
}

inline void Modify(int o,int l,int r,int pos)
{
if (l == r)
{
Left[o] = Right[o] = Val[Name[l]]; return;
}
int mid = l + r >> 1;
if (pos <= mid) Modify(o<<1,l,mid,pos);
else Modify(o<<1|1,mid+1,r,pos);
Left[o] = Left[o<<1] + Left[o<<1|1];
Right[o] = Right[o<<1|1] + Right[o<<1];
}

inline data Walk_Left(int x,int y)
{
int TP = 0; data ret; ret.v0 = 0; ret.v1 = Max;
for (; DP[x] >= DP[y]; x = fa[x][0])
if (!Huge[x]) s2[++TP] = Val[x];
else
{
if (dfn[x] == lt[bel[x]] && DP[Name[ft[bel[x]]]] >= DP[y])
s2[++TP] = L[bel[x]],x = Quickfa(x,pos[x] - 1);
else
{
if (DP[x] - pos[x] + 1 >= DP[y])
{
s2[++TP] = Query_Left(dfn[x] - pos[x] + 1,dfn[x]);
x = Quickfa(x,pos[x] - 1);
}
else s2[++TP] = Query_Left(dfn[y],dfn[x]),x = y;
}
}
for (int i = TP; i > 0; i--) ret = ret + s2[i]; return ret;
}

inline data Walk_Right(int x,int y)
{
int TP = 0; data ret; ret.v0 = 0; ret.v1 = Max;
for (; DP[x] >= DP[y]; x = fa[x][0])
if (!Huge[x]) s2[++TP] = Val[x];
else
{
if (dfn[x] == lt[bel[x]] && DP[Name[ft[bel[x]]]] >= DP[y])
s2[++TP] = R[bel[x]],x = Quickfa(x,pos[x] - 1);
else
{
if (DP[x] - pos[x] + 1 >= DP[y])
{
s2[++TP] = Query_Right(dfn[x] - pos[x] + 1,dfn[x]);
x = Quickfa(x,pos[x] - 1);
}
else s2[++TP] = Query_Right(dfn[y],dfn[x]),x = y;
}
}
for (int i = 1; i <= TP; i++) ret = ret + s2[i]; return ret;
}

int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
freopen("t1.txt","w",stdout);
#endif

n = Read(); m = Read(); k = Read(); Max = mi[0] = 1;
for (int i = 1; i < k; i++) mi[i] = mi[i - 1] << (u64)(1),Max += mi[i];
for (int i = 1; i <= n; i++)
{
typ[i] = Read(); A[i] = Read();
Val[i].v0 = Opt(0,A[i],typ[i]);
Val[i].v1 = Opt(Max,A[i],typ[i]);
}
for (int i = 1; i < n; i++)
{
int x = Read(),y = Read();
v[x].push_back(y); v[y].push_back(x);
}
DP[1] = 1; Dfs1(1,0); Dfs2(1,0); Build(1,1,n);
for (int i = 1; i <= tot; i++)
{
L[i] = Query_Left(ft[i],lt[i]);
R[i] = Query_Right(ft[i],lt[i]);
}

while (m--)
{
u64 com = Read(),x,y,z;
x = Read(); y = Read(); z = Read();
if (com == 1)
{
int lca = LCA(x,y); data now;
if (lca == x) now = Walk_Left(y,x);
else if (lca == y) now = Walk_Right(x,y);
else now = Walk_Right(x,lca) + Walk_Left(y,Quickfa(y,DP[y] - DP[lca] - 1));

u64 Ans,sum; Ans = sum = 0;
for (int i = k - 1; i >= 0; i--)
{
u64 A,B; B = now.v0 & mi[i];
A = ((sum | mi[i]) <= z) ? now.v1 & mi[i] : 0;
if (B >= A) Ans |= B; else Ans |= A,sum |= mi[i];
}
Print(Ans);
}
else
{
typ[x] = y; A[x] = z;
Val[x].v0 = Opt(0,A[x],typ[x]);
Val[x].v1 = Opt(Max,A[x],typ[x]);
Modify(1,1,n,dfn[x]);
if (Huge[x])
{
L[bel[x]] = Query_Left(ft[bel[x]],lt[bel[x]]);
R[bel[x]] = Query_Right(ft[bel[x]],lt[bel[x]]);
}
}
}

//cerr << (double)(clock()) / CLOCKS_PER_SEC << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: