4811: [Ynoi2017]由乃的OJ

Time Limit: 6 Sec  Memory Limit: 256 MB
Submit: 366  Solved: 118
[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
#include <bits/stdc++.h>
using namespace std;
#define maxn 100005
vector<vector<int> >g(maxn);
struct point{int op;unsigned long long v;
}a[maxn];
struct tree{unsigned long long v0, v1;tree() {};friend tree operator + (tree x, tree y){    //重载+方便后面合并操作tree z;z.v0 = (x.v0 & y.v1) | ((~x.v0) & y.v0);z.v1 = (x.v1 & y.v1) | ((~x.v1) & y.v0);return z;}tree (int op, unsigned long long v){  //构造函数if(op == 1){v0 = 0 & v;v1 = (~0) & v;}if(op == 2){v0 = 0 | v;v1 = (~0) | v;}if(op == 3){v0 = 0 ^ v;v1 = (~0) ^ v;}}
}cl[maxn << 2], cr[maxn << 2]; //因为从结点x走到y,链剖后的分段路径会有从上到下和从下到上的区别,这里需要区分
int sz[maxn], id[maxn], dep[maxn], son[maxn], top[maxn],  pre[maxn], val[maxn], tot;
void dfs(int x, int fa, int d){sz[x] = 1;pre[x] = fa;dep[x] = d;son[x] = 0;int cur;for(int i = 0; i < g[x].size(); ++i){cur = g[x][i];if(cur == fa) continue;dfs(cur, x, d + 1);sz[x] += sz[cur];if(sz[son[x]] < sz[cur]){son[x] = cur;}}
}
void dfs1(int x, int tp){id[x] = ++tot;top[x] = tp;if(son[x]) dfs1(son[x], tp);int cur;for(int i = 0; i < g[x].size(); ++i){cur = g[x][i];if(cur == pre[x] || cur == son[x]) continue;dfs1(cur, cur);}
}
void build(int o, int l, int r){if(l == r){cl[o] = cr[o] = tree(a[val[l]].op, a[val[l]].v);return;}int mid = l + r >> 1;build(o << 1, l, mid);build(o << 1 | 1, mid + 1, r);cl[o] = cl[o << 1] + cl[o << 1 | 1];cr[o] = cr[o << 1 | 1] + cr[o << 1];   //合并上的区别,值得注意
}
void add(int o, int l, int r, int pos, int op, unsigned long long z){if(l == r){cl[o] = cr[o] = tree(op, z);return;}int mid = l + r >> 1;if(pos <= mid) add(o << 1, l, mid, pos, op, z);else add(o << 1 | 1, mid + 1, r, pos, op, z);cl[o] = cl[o << 1] + cl[o << 1 | 1];   //注意合并的顺序cr[o] = cr[o << 1 | 1] + cr[o << 1];
}
tree query(int o, int l, int r, int L, int R, int kind){if(l >= L && r <= R){if(kind == 1) return cl[o];return cr[o];}int mid = l + r >> 1;if(mid >= R) return query(o << 1, l, mid, L, R, kind);else if(mid < L) return query(o << 1 | 1, mid + 1, r, L, R, kind);else{if(kind == 1) return query(o << 1, l, mid, L, R, kind) + query(o << 1 | 1, mid + 1, r, L, R, kind);else return query(o << 1 | 1, mid + 1, r, L, R, kind) + query(o << 1, l, mid, L, R, kind);    //注意合并的顺序}
}
unsigned long long getsm(int x, int y, unsigned long long z, int k){int tp1 = top[x], tp2 = top[y];tree ansx = tree(3, 0), ansy = tree(3, 0);while(tp1 != tp2){if(dep[tp1] < dep[tp2]){ansy = query(1, 1, tot, id[tp2], id[y], 1) + ansy;   //还是注意顺序。。。。y = pre[tp2];tp2 = top[y];}else{ansx = ansx + query(1, 1, tot, id[tp1], id[x], 2);x = pre[tp1];tp1 = top[x];   }}if(dep[x] < dep[y]){ansx = ansx + query(1, 1, tot, id[x], id[y], 1) + ansy;   //注意合并的顺序}else{ansx = ansx + query(1, 1, tot, id[y], id[x], 2) + ansy;}unsigned long long res = 0, cost = 0;for(int i = k - 1; i >= 0; --i){   //这里一定全程unsigned long long!!!!if((ansx.v0 >> i) & 1ULL * 1){res |= 1ULL * 1 << i;}else if((ansx.v1 >> i) & 1ULL * 1){if((cost | (1ULL * 1 << i)) <= z){res |= 1ULL * 1 << i;cost |= 1ULL * 1 << i;}}}return res;
}
int main(){int n, m, k, u, v, q;unsigned long long z;scanf("%d %d %d", &n, &m, &k);for(int i = 1; i <= n; ++i){scanf("%d %llu", &a[i].op, &a[i].v);}for(int i = 1; i < n; ++i){scanf("%d %d", &u, &v);g[u].push_back(v);g[v].push_back(u);}tot = 0;dfs(1, 0, 1);dfs1(1, 1);for(int i = 1; i <= n; ++i){val[id[i]] = i;}build(1, 1, tot);for(int i = 1; i <= m; ++i){scanf("%d %d %d %llu", &q, &u, &v, &z);if(q == 2){add(1, 1, tot, id[u], v, z);}else{printf("%llu\n", getsm(u, v, z, k));}}
}/*
题意:一棵树,1e5个结点,每个结点一个操作(&,|,^)和一个数值。1e5次操作 ,每次操作要么修改每个结点的操作和
数值,要么询问路径x到y上,在[0,z]中找个数对和每个结点上的数字进行一次该结点上的操作,使得最终答案最大。思路:一开始想可以直接把操作和数字合并啊,然后直接树链剖分然后线段树维护区间值,然后发现naive了,&,|,^这三个
位运算没办法用一个数搞定,那么就用两个数好了。。。。v0,v1分别状压(这三种位运算是位独立的,位和位互不影响)表示每一位
原本是0经过操作后得到什么,和原本是1经过操作后得到什么。所以操作&和数字可以合并为v0 = 0 & v; v1 = (~0) & v, 其余的类推,然后我们
就不用管操作符了。之后就可以用线段树维护区间的值了,这里我们得讨论合并操作,就是v0在经过x,再经过y后怎么表示。
首先v0在经过x后,有些位变成1了,这个时候我们用v1.y更新这些位,很容易理解吧,即 (x.v0 & y.v1);还有一些位没有变成0,还
保持着0怎么办,当然用v0.y更新这些位了- -||.即((~x.v0) & y.v0),x.v0取非的原因是还保持0的那些位直接&的话一定是0,无法体现
y.v0的作用,实际上这里如果单独考虑还是0的位直接用y.v0就好了,但是避免不是0的位的影响,所以用~x.v0,这样非0的变成0,不考虑这些位,
为0的变成1,和y.v0 &,保留y.v0对这些位的贡献。然后 | 一下就好了,合并两者各自位的贡献。注意:从x到y后操作的先后顺序,这样我们需要区分合并区间的顺序,这个很简单,用两个数组存就好了,合并的时候注意一下。然后由于最大64
位,全程都用unsigned long long!!!WA了多次才意识到。。。。
*/

BZOJ-4811: [Ynoi2017]由乃的OJ (树链剖分 线段树维护区间操作值 好题)相关推荐

  1. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 1153  Solved: 421 [Submit][Sta ...

  2. BZOJ3862Little Devil I——树链剖分+线段树

    题目大意: 给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作: 1.将u到v路径上所有边颜色翻转(黑->白,白->黑) 2.将只有一个点在u到v路径上的边颜色翻转 3.查询u到 ...

  3. CodeForces - 160D Edges in MST(思维+tarjan/树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一张 n 个点 m 条边组成的带权无向图,现在对于每条边来说,确定一下其分类: 一定是最小生成树上的边 可能是最小生成树上的边 一定不是最小生成树的边 题目分析:两种 ...

  4. CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)

    题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...

  5. P2486 [SDOI2011]染色(树链剖分+线段树)

    题干描述 输入描述 输出格式 对于每个询问操作,输出一行答案. 输入输出样例 输入 #1 复制 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C 2 1 1 Q ...

  6. YbtOJ-染色计划【树链剖分,线段树,tarjan】

    正题 题目大意 给出nnn个点的一棵树,每个点有个颜色aia_iai​,你每次可以选择一个颜色全部变成另一个颜色. 求最少多少次操作可以把一种颜色变成一个完整的连通块. 1≤k≤n≤2×1051\le ...

  7. BZOJ4127Abs——树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

  8. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  9. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  10. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

    题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...

最新文章

  1. 衡量微型计算机的性能指标参数有哪些,衡量计算机性能的主要技术指标有哪些?...
  2. zabbix监控系统客户端安装
  3. MFC单文档程序加载web网站和html文件
  4. 攻防世界Reverse第八题logmein
  5. 【论文解读】这篇顶会paper,讲述了疫情期间憋疯的你和我
  6. SGS 客户端协议解析
  7. osgEarth用户手册
  8. android视频教程
  9. 修改Fiddler实用插件JsonViewer
  10. 三星+android+7.0+自动纠正单词,升级党必看!三星S/Note系列更新Android 7.0指南
  11. iOS-最全的App上架教程
  12. java反射怎么获取结构体_java反射-使用反射获取类的所有信息
  13. Swift 中的过滤器
  14. pymongo使用经验
  15. 配置管理计划的主要内容有哪些?
  16. 一个好用的hibernate泛型dao
  17. 蓝牙电话之HFP-连接
  18. 基于Unity的2D像素风闯关游戏Demo——SunnyLand
  19. web前端编程实战实例:制作静态京东首页
  20. 如何用搜狗拼音输入法输入希腊字母

热门文章

  1. 微商是如何推广的呢?
  2. QuickBooks 2020 for Mac(mac财务管理软件)
  3. 自定义注解和AOP的结合
  4. 发一个随机红包 100块钱给10个人 每个人最多12块钱 最少6块钱 怎么分
  5. 一个产品经理的自述:我在腾讯工作的这一年
  6. 知识管理的唯一出路:与业务融合,构建情景化知识管理体系
  7. 拿到6个重磅offer的大神,超详细面试经验总结
  8. UMLChina建模竞赛第3赛季第10轮:汽车、EA
  9. 讯搜全文检索引擎-服务器部署
  10. 论文总结(一)—基于深度学习的普通遥感图像质量改进