题目链接:

闲扯:

终于在集训中敲出正解(虽然与正解不完全相同),开心QAQ

首先比较巧,这题是\(Ebola\)出的一场模拟赛的一道题的树上强化版,当时还口胡出了那题的题解

然而考场上只得了86最后一个substask被卡了,一开始以为毒瘤出题人卡常(虽然真卡了)卡线段树,题目时限1.5s,评测机上两个点擦线1500ms左右,剩下两个点不知道。然后本地测一下都是1900+ms!机子性能已经这样了吗....结果把快读换成\(fread\),TM过了!最慢的1200+ms!!!这......无话可说,\(getchar()\)快读也卡讲究

分析:

首先最简单的处理不讲了.就是把每个点的未知数表示成\(k_i x_1 + b_i\)的形式,这DFS一遍就好了

然后观察到有一个1e3的子任务,想想暴力怎么做,我们对于操作1,相当于\((k_i+k_j)x_1+(b_i+b_j)=w\)判断一下解得情况就好了,\(O(1)\)完成;

对于操作2,我们可以发现对于\(x\)的操作,只会对\(x\)的子树中的\(k_ix_1+b_i\)形式有影响(实际上只会影响\(b_i\)),于是\(DFS\)一遍子树即可,这样总的暴力时间复杂度是\(O(nq)\)

考虑优化暴力,

我们发现瓶颈是操作2,如果将\(x\)与其父亲的边权从\(w_1\)改为\(w_2\),那么加入\(x\)本来形式是\(k_ix_1+b_i\),这时候变成了\(k_i x_1+b_i+w_2-w_1\),相当于加操作,当时在\(x\)的子树中与\(x\)的\(k_i\)(实际上显然只有-1,1两种取值)不同的点,\(b\)值却应该减去\(w_2-w_1\),所以我们将标记开成一个二元组,一个记录标记的正负,另一个记录值,重载下运算符就很方便了

  1. struct Tag{
  2. int o;//标记的正负
  3. ll dt;
  4. Tag(){o=dt=0;}
  5. Tag(int o){o=dt=o;}
  6. Tag(int _o,ll _dt){o=_o,dt=_dt;}
  7. Tag operator +(const Tag &b)const{
  8. Tag tmp=*this;
  9. if(tmp.o==0)tmp=b;
  10. else if(b.o==0)return tmp;
  11. else {
  12. if(o!=b.o){
  13. tmp.dt=dt-b.dt;
  14. }
  15. else tmp.dt=dt+b.dt;
  16. }
  17. return tmp;
  18. }
  19. };

这样对于操作2,只用在子树加个标记就好了,因为dfs序是一段连续区间(我比较傻考场上是用树链剖分)使用线段树就好了

对于操作1,我们两次单点查询就好了,然后按暴力那样处理.

总的时间复杂度\(O(q log N)\),常数稍大

当然标算std是将深度分奇偶考虑,然后树状数组维护差分标记,时间复杂度相同但是常数小的多

代码

这是考场代码换了快读,如果想看线段树部分直接跳到\(niconicoi\)那个\(namespace\)就好了

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cctype>
  5. #include <algorithm>
  6. #include <queue>
  7. #include <cmath>
  8. #include <vector>
  9. #define ll long long
  10. #define ri register int
  11. using std::min;
  12. using std::abs;
  13. using std::max;
  14. inline char nc(){
  15. static char buf[100000],*p1=buf,*p2=buf;
  16. return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
  17. }
  18. template <class T>inline void read(T &x){
  19. x=0;int ne=0;char c;
  20. while(!isdigit(c=nc()))ne=c=='-';
  21. x=c-48;
  22. while(isdigit(c=nc()))x=(x<<3)+(x<<1)+c-48;
  23. x=ne?-x:x;return ;
  24. }
  25. const int maxn=100005;
  26. const int inf=0x7fffffff;
  27. const int N=1000005;
  28. struct Edge{
  29. int ne,to;
  30. ll dis;
  31. }edge[N<<1];
  32. int h[N],num_edge=1;
  33. inline void add_edge(int f,int to,int c){
  34. edge[++num_edge].ne=h[f];
  35. edge[num_edge].to=to;
  36. edge[num_edge].dis=c;
  37. h[f]=num_edge;
  38. }
  39. struct Wt{
  40. int ki;
  41. ll bi;
  42. Wt(){ki=bi=0;}
  43. Wt(int _k,ll _b){ki=_k,bi=_b;}
  44. }pt[N];
  45. int n,q;
  46. int fafa[N],fa_id[N];
  47. namespace wtf{
  48. void main(){
  49. /*orz*/
  50. return ;
  51. }
  52. }
  53. void pre_dfs(int now,int fa){
  54. int v;
  55. int x=pt[now].ki,y=pt[now].bi;
  56. for(ri i=h[now];i;i=edge[i].ne){
  57. v=edge[i].to;
  58. if(v==fa)continue;
  59. fafa[v]=now;
  60. fa_id[v]=i;
  61. pt[v]=Wt(-x,edge[i].dis-y);
  62. pre_dfs(v,now);
  63. }
  64. return;
  65. }
  66. namespace qwq{
  67. void main(){
  68. int op,x,y;ll dd;
  69. ll p=edge[2].dis;
  70. while(q--){
  71. read(op),read(x),read(y);
  72. if(op==1){
  73. read(dd);
  74. if(x!=y){
  75. if(dd==p){
  76. puts("inf");
  77. }
  78. else{
  79. puts("none");
  80. }
  81. }
  82. else {
  83. if(x==1){
  84. if(dd%2)puts("none");
  85. else printf("%lld\n",dd/2);
  86. }
  87. if(x==2){
  88. ll tt=2*p-dd;
  89. if(tt%2)puts("none");
  90. else printf("%lld\n",tt/2);
  91. }
  92. }
  93. }
  94. else{
  95. p=y;
  96. }
  97. }
  98. return ;
  99. }
  100. }
  101. namespace task_1{
  102. void main(){
  103. int op,x,y;ll dd;
  104. int kk,bb;
  105. while(q--){
  106. read(op),read(x),read(y);
  107. if(op==1){
  108. read(dd);
  109. kk=pt[x].ki+pt[y].ki;
  110. bb=pt[x].bi+pt[y].bi;
  111. dd=dd-bb;
  112. if(kk==0){
  113. if(dd==0)puts("inf");
  114. else puts("none");
  115. }
  116. else if(dd%abs(kk)!=0)puts("none");
  117. else printf("%lld\n",dd/kk);
  118. }
  119. else {
  120. edge[fa_id[x]].dis=y;
  121. edge[fa_id[x]^1].dis=y;
  122. pre_dfs(fafa[x],fafa[fafa[x]]);
  123. }
  124. }
  125. return ;
  126. }
  127. }
  128. namespace niconiconi{
  129. int dep[N],top[N],son[N],size[N],dfn[N],rnk[N],tot=0;
  130. void print(ll xxx){
  131. if(!xxx)return ;
  132. print(xxx/10);
  133. putchar(xxx%10+'0');
  134. return ;
  135. }
  136. void dfs_1(int now){
  137. int v;size[now]=1;
  138. for(ri i=h[now];i;i=edge[i].ne){
  139. v=edge[i].to;
  140. if(v==fafa[now])continue;
  141. dep[v]=dep[now]+1;
  142. dfs_1(v);
  143. size[now]+=size[v];
  144. if(!son[now]||size[son[now]]<size[v])son[now]=v;
  145. }
  146. return ;
  147. }
  148. void dfs_2(int now,int t){
  149. int v;top[now]=t;
  150. dfn[now]=++tot,rnk[tot]=now;
  151. if(!son[now])return ;
  152. dfs_2(son[now],t);
  153. for(ri i=h[now];i;i=edge[i].ne){
  154. v=edge[i].to;
  155. if(v==fafa[now]||v==son[now])continue;
  156. dfs_2(v,v);
  157. }
  158. return ;
  159. }
  160. struct Tag{
  161. int o;//标记的正负
  162. ll dt;
  163. Tag(){o=dt=0;}
  164. Tag(int o){o=dt=o;}
  165. Tag(int _o,ll _dt){o=_o,dt=_dt;}
  166. Tag operator +(const Tag &b)const{
  167. Tag tmp=*this;
  168. if(tmp.o==0)tmp=b;
  169. else if(b.o==0)return tmp;
  170. else {
  171. if(o!=b.o){
  172. tmp.dt=dt-b.dt;
  173. }
  174. else tmp.dt=dt+b.dt;
  175. }
  176. return tmp;
  177. }
  178. };
  179. Tag tag[N<<2];
  180. void build(int now,int l,int r){
  181. tag[now]=Tag(0);
  182. if(l==r){
  183. return ;
  184. }
  185. int mid=(l+r)>>1;
  186. build(now<<1,l,mid);
  187. build(now<<1|1,mid+1,r);
  188. return ;
  189. }
  190. int L,R;
  191. Tag dta;
  192. inline void pushdown(int now){
  193. if(tag[now].o==0)return ;
  194. tag[now<<1]=tag[now<<1]+tag[now];
  195. tag[now<<1|1]=tag[now<<1|1]+tag[now];
  196. tag[now]=Tag(0);
  197. return ;
  198. }
  199. void update(int now,int l,int r){
  200. if(L<=l&&r<=R){
  201. tag[now]=tag[now]+dta;
  202. return ;
  203. }
  204. int mid=(l+r)>>1;
  205. pushdown(now);
  206. if(L<=mid)update(now<<1,l,mid);
  207. if(mid<R)update(now<<1|1,mid+1,r);
  208. return ;
  209. }
  210. Wt pa,pb;
  211. int t;
  212. void query(int now,int l,int r){
  213. if(l==r){
  214. //int kkk=pt[rnk[l]].ki,bbb=pt[rnk[l]].bi;
  215. if(tag[now].o!=0){
  216. if(tag[now].o!=pt[rnk[l]].ki){
  217. pt[rnk[l]].bi-=tag[now].dt;
  218. }
  219. else{
  220. pt[rnk[l]].bi+=tag[now].dt;
  221. }
  222. tag[now]=Tag(0);
  223. }
  224. //pa.ki=pt[rnk[l]].ki;
  225. //pa.bi=pt[rnk[l]].bi;
  226. return;
  227. }
  228. int mid=(l+r)>>1;
  229. pushdown(now);
  230. if(t<=mid)query(now<<1,l,mid);
  231. else query(now<<1|1,mid+1,r);
  232. return ;
  233. }
  234. void main(){
  235. int op,x,y;
  236. ll kk,bb,dd;
  237. dep[1]=0;
  238. dfs_1(1);
  239. dfs_2(1,1);
  240. build(1,1,n);
  241. while(q--){
  242. read(op),read(x),read(y);
  243. if(op==1){
  244. read(dd);
  245. t=dfn[x];//pa=Wt(0,0);
  246. query(1,1,n);
  247. t=dfn[y];//pb=Wt(pa.ki,pa.bi),pa=Wt(0,0);
  248. query(1,1,n);
  249. //printf("%d %d %d %d\n",pa.ki,pb.ki,pa.bi,pb.bi);
  250. kk=pt[x].ki+pt[y].ki;
  251. bb=pt[x].bi+pt[y].bi;
  252. dd=dd-bb;
  253. if(kk==0){
  254. if(dd==0)puts("inf");
  255. else puts("none");
  256. }
  257. else if(dd%abs(kk)!=0)puts("none");
  258. else {
  259. if(dd==0)puts("0");
  260. else {
  261. dd=dd/kk;
  262. if(dd<0)dd=-dd,putchar('-');
  263. print(dd);
  264. puts("");
  265. }
  266. //printf("%lld\n",dd/kk);
  267. }
  268. }
  269. else {
  270. dd=edge[fa_id[x]].dis;
  271. edge[fa_id[x]].dis=edge[fa_id[x]^1].dis=y;
  272. dd=1ll*y-dd;
  273. //printf("%lld\n",dd);
  274. L=dfn[x],R=dfn[x]+size[x]-1;
  275. //t=dfn[x];pa=Wt(0,0);
  276. //query(1,1,n);
  277. pa=pt[x];
  278. //printf("%d\n",pa.ki);
  279. dta=Tag(pa.ki,dd);
  280. update(1,1,n);
  281. //update_subtree()
  282. }
  283. }
  284. return ;
  285. }
  286. }
  287. int main(){
  288. int x,y;
  289. freopen("equation.in","r",stdin);
  290. freopen("equation.out","w",stdout);
  291. read(n),read(q);
  292. for(ri i=2;i<=n;i++){
  293. read(x),read(y);
  294. add_edge(i,x,y);
  295. add_edge(x,i,y);
  296. }
  297. pt[1].ki=1,pt[1].bi=0;
  298. fafa[1]=0;
  299. pre_dfs(1,0);
  300. if(q==0)wtf::main();
  301. else if(n==2)qwq::main();
  302. else if(n<=2000)task_1::main();
  303. else niconiconi::main();
  304. fclose(stdin);
  305. fclose(stdout);
  306. return 0;
  307. }

[NOIP10.6模拟赛]2.equation题解--DFS序+线段树的更多相关文章

  1. BZOJ 3252题解(贪心+dfs序+线段树)

    题面 传送门 分析 此题做法很多,树形DP,DFS序+线段树,树链剖分都可以做 这里给出DFS序+线段树的代码 我们用线段树维护到根节点路径上节点权值之和的最大值,以及取到最大值的节点编号x 每次从根 ...

  2. 【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树

    题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\), ...

  3. BZOJ1103 [POI2007]大都市meg dfs序 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1103 题意概括 一棵树上,一开始所有的边权值为1,我们要支持两种操作: 1. 修改某一条边的权值为 ...

  4. CodeForces 877E Danil and a Part-time Job(dfs序+线段树)

    Danil decided to earn some money, so he had found a part-time job. The interview have went well, so ...

  5. 洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)

    P3178 [HAOI2015]树上操作 题目链接:https://www.luogu.org/problemnew/show/P3178 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边 ...

  6. CodeForces 877E DFS序+线段树

    CodeForces 877E DFS序+线段树 题意 就是树上有n个点,然后每个点都有一盏灯,给出初始的状态,1表示亮,0表示不亮,然后有两种操作,第一种是get x,表示你需要输出x的子树和x本身 ...

  7. [51nod 1681]公共祖先(dfs序+线段树合并)

    [51nod 1681]公共祖先(dfs序+线段树合并) 题面 给出两棵n(n<=100000)个点的树,对于所有点对求它们在两棵树中公共的公共祖先数量之和. 如图,对于点对(2,4),它们在第 ...

  8. 牛客wannafly 挑战赛14 B 前缀查询(trie树上dfs序+线段树)

    牛客wannafly 挑战赛14 B 前缀查询(trie树上dfs序+线段树) 链接:https://ac.nowcoder.com/acm/problem/15706 现在需要您来帮忙维护这个名册, ...

  9. codevs1228 (dfs序+线段树)

    1228 苹果树  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题目描述 Description 在卡卡的房子外面,有一棵苹果树.每年的春天,树上总会结 ...

随机推荐

  1. win10系统搭建vagrant时开启bios,虚拟化问题

    VT-x is disabled in the BIOS的意思是VT-X虚拟化技术处于禁止关闭状态,需要在电脑主板BIOS中开启CPU虚拟化技术thinkpad重启F1进入BIOS,选择: Sercu ...

  2. SqlServer自动锁定sa解决代码

    ALTER LOGIN sa ENABLE ; GO ALTER LOGIN sa WITH PASSWORD = '' unlock, check_policy = off, check_expir ...

  3. 在基于Android以及Jetson TK平台上如何写32位的Thumb-2指令

    由于Android以及Jetson TK的编译工具链中的汇编器仍然不支持大部分的32位Thumb-2指令,比如add.w,因此我们只能通过手工写机器指令码来实现想要的指令.下面我将简单地介绍如何在AR ...

  4. 使用VLC发送TS流与播放TS流

    使用VLC发送TS流与播放TS流 一.如何使用VLC发送TS流 1.添加一个文件至VLC 2.选择串流,继续 3.选择UDP,点击添加 4.输入地址及端口 5.选择h.264+mp3(TS) 6.ne ...

  5. SQL Server 高级函数汇总【转】

    看到一个帖子,博主收集的很全,里面涵盖了一些常用的内置函数,特此收藏下: 原文链接:https://blog.csdn.net/wang1127248268/article/details/53406 ...

  6. Crontab的格式说明

    第1列分钟1-59第2列小时1-23(0表示子夜)第3列日1-31第4列月1-12第5列星期0-6(0表示星期天)第6列要运行的命令 下面是crontab的格式:分 时 日 月 星期 要运行的命令 这 ...

  7. 简单范例php调用C# WebService

    准备工作:1. 安装IIS对于PHP的支持,看这里2. 要调用Web Service需要nusoap支持,只要弄个nusoap.php就可以了,把它放在要运行的php文件能够引用的地方,比如我放在同一 ...

  8. 解决报错Fatal error in launcher

    换电脑重装python,打算安装第三方库的时候出现错误: Fatal error in launcher 然而在网上搜到的大多数是解决 —— Fatal error in launcher: Unab ...

  9. docker教程(1) - 快速使用

    docker 笔记(1) --docker安装.获取镜像.启动容器.删除容器 一.安装 Docker 官方文档 根据官方文档整理简单流程 从Docker Hub下载mac包 运行磁盘镜像,将Docke ...

  10. 跨域跨域跨域,从此say goodbye

    跨域这个问题每个开发者都会遇到,只是时间先后而已,你不搞清楚它他就像狗皮膏药一样粘着你,在你求职生涯中不停的遇到,然后你每次都要做这个功课,终于有一天这个名词已经让我忍无可忍了,下定决心必须搞定它,要 ...