1. 程式人生 > >[BZOJ]4811: [Ynoi2017]由乃的OJ

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

最大 ear tps 註冊 i++ script col P20 一個

 題解: 上一題的系列套路題 但是上一題 我們用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

By 佚名提供

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