[BZOJ]4811: [Ynoi2017]由乃的OJ
题解: 上一题的系列套路题 但是上一题 我们用n*log^3(n)水过了 这题6s明显是不可行的 需要优化一下复杂度 我们考虑线段树合并 维护每一位输入为0/1的时候输出 然后做区间合并 这样子平方转移依然是3个log的 我们想想二进制优化 让每一位对应unsigned long long每一二进制位然后把每次合并后的结果都用一个64位无符号整数存下来 这样就成2个log了 具体怎么合并 可以手推下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <stack> #include <queue> #include <cmath> #include <set> #include <map> #define mp make_pair #define pb push_back #define link(x) for(edge *j=h[x];j;j=j->next) #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=1e5+10; const double eps=1e-8; #define ll unsigned long long #define pii pair<ll,ll> using namespace std; struct edge{ int t;edge*next;}e[MAXN<<1],*h[MAXN],*o=e; void add( int x, int y){o->t=y;o->next=h[x];h[x]=o++;} inline ll read() { ll ret=0; char gc= getchar (); while (gc< '0' ||gc> '9' ) gc= getchar (); while (gc>= '0' &&gc<= '9' ) ret=ret*10+(gc- '0' ),gc= getchar (); return ret; } ll l0[MAXN<<2],l1[MAXN<<2],r0[MAXN<<2],r1[MAXN<<2]; int opt[MAXN],n,m,k; ll a[MAXN],base; void up( int x){ l0[x]=(l1[x<<1|1]&l0[x<<1])|((~l0[x<<1])&l0[x<<1|1]); l1[x]=(l1[x<<1]&l1[x<<1|1])|((~l1[x<<1])&l0[x<<1|1]); r0[x]=(r0[x<<1|1]&r1[x<<1])|((~r0[x<<1|1])&r0[x<<1]); r1[x]=(r1[x<<1|1]&r1[x<<1])|((~r1[x<<1|1])&r0[x<<1]); } void Opt1( int x,ll y){ l0[x]=r0[x]=0; l1[x]=r1[x]=y; } void Opt2( int x,ll y){ l0[x]=r0[x]=y; l1[x]=r1[x]=base; } void Opt3( int x,ll y){ l0[x]=r0[x]=y; l1[x]=r1[x]=(base^y); } int tp[MAXN],p[MAXN],fp[MAXN],cnt; void built( int x, int l, int r){ if (l==r){ if (opt[fp[l]]==1)Opt1(x,a[fp[l]]); else if (opt[fp[l]]==2)Opt2(x,a[fp[l]]); else Opt3(x,a[fp[l]]); return ; } int mid=(l+r)>>1; built(x<<1,l,mid); built(x<<1|1,mid+1,r); up(x); } void update( int x, int l, int r, int t){ if (l==r){ if (opt[fp[l]]==1)Opt1(x,a[fp[l]]); else if (opt[fp[l]]==2)Opt2(x,a[fp[l]]); else Opt3(x,a[fp[l]]); return ; } int mid=(l+r)>>1; if (t<=mid)update(x<<1,l,mid,t); else update(x<<1|1,mid+1,r,t); up(x); } pii ans; void query1( int x, int l, int r, int ql, int qr){ if (ql<=l&&r<=qr){ ans.first=(ans.first&l1[x])|(~ans.first&l0[x]); ans.second=(ans.second&l1[x])|(~ans.second&l0[x]); return ; } int mid=(l+r)>>1; if (ql<=mid)query1(x<<1,l,mid,ql,qr); if (qr>mid)query1(x<<1|1,mid+1,r,ql,qr); } void query2( int x, int l, int r, int ql, int qr){ if (ql<=l&&r<=qr){ ans.first=(ans.first&r1[x])|(~ans.first&r0[x]); ans.second=(ans.second&r1[x])|(~ans.second&r0[x]); return ; } int mid=(l+r)>>1; if (qr>mid)query2(x<<1|1,mid+1,r,ql,qr); if (ql<=mid)query2(x<<1,l,mid,ql,qr); } int son[MAXN],num[MAXN],dep[MAXN],fa[MAXN]; void dfs1( int x, int pre, int deep){ fa[x]=pre;num[x]=1;dep[x]=deep+1; link(x) if (j->t!=pre){ dfs1(j->t,x,deep+1); num[x]+=num[j->t]; if (son[x]==-1||num[son[x]]<num[j->t])son[x]=j->t; } } void dfs2( int x, int td){ tp[x]=td;p[x]=++cnt;fp[p[x]]=x; if (son[x]!=-1)dfs2(son[x],td); link(x) if (j->t!=son[x]&&j->t!=fa[x])dfs2(j->t,j->t); } pii st[MAXN]; int tot; void solve( int u, int v,ll z){ int uu=tp[u]; int vv=tp[v]; ans.first=0;ans.second=base; tot=0; while (uu!=vv){ if (dep[uu]>dep[vv])query2(1,1,n,p[uu],p[u]),u=fa[uu],uu=tp[u]; else st[++tot]=mp(p[vv],p[v]),v=fa[vv],vv=tp[v]; } if (dep[u]>dep[v])query2(1,1,n,p[v],p[u]); else query1(1,1,n,p[u],p[v]); dec(i,tot,1)query1(1,1,n,st[i].first,st[i].second); ll ans1=0;ll maxx=0; for ( int i=k-1;i>=0;i--){ int t1=((ans.first>>i)&1); int t2=((ans.second>>i)&1); if (t1&&t2)maxx+=(1ll<<i); else if (t1&&!t2)maxx+=(1ll<<i); else if (!t1&&t2){ if (ans1+(1ll<<i)<=z)ans1+=(1ll<<i),maxx+=(1ll<<i); } } printf ( "%llu\n" ,maxx); } int main(){ n=read();m=read();k=read(); for ( int i=0;i<k;i++)base|=(1ULL<<i); inc(i,1,n)son[i]=-1; inc(i,1,n)opt[i]=read(),a[i]=read(); int u,v; inc(i,2,n)u=read(),v=read(),add(u,v),add(v,u); dfs1(1,0,0);dfs2(1,1);built(1,1,n); int x,y,op;ll z; while (m--){ op=read();x=read();y=read();z=read(); if (op==1)solve(x,y,z); else opt[x]=y,a[x]=z,update(1,1,n,p[x]); } return 0; } |
4811: [Ynoi2017]由乃的OJ
Time Limit: 6 Sec Memory Limit: 256 MBSubmit: 740 Solved: 271
[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
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
1
5