4811: [Ynoi2017]由乃的OJ

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

[ 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[N]; 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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值