[BZOJ]4811: [Ynoi2017]由乃的OJ

 题解:   上一题的系列套路题  但是上一题 我们用n*log^3(n)水过了  这题6s明显是不可行的  需要优化一下复杂度  我们考虑线段树合并 维护每一位输入为0/1的时候输出 然后做区间合并  这样子平方转移依然是3个log的  我们想想二进制优化  让每一位对应unsigned long long每一二进制位然后把每次合并后的结果都用一个64位无符号整数存下来  这样就成2个log了  具体怎么合并 可以手推下

#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 MB
Submit: 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

Sample Output

7
1
5

HINT

 

Source

posted @ 2019-02-11 22:37  wang9897  阅读(297)  评论(0编辑  收藏  举报