[LCT动态树] [NOI2014]魔法森林,[ZJOI2018]历史

[NOI2014] 魔法森林

题目

按照aaa精灵从小到大排序

按顺序插入每一条边

加入第iii条边后的最小代价为a[i]a[i]a[i]加上从111nnn的所有路径中最大bbb最小的路径代价

维护边权 把边在LCTLCTLCT中理解为点?——看题解代码其实就是建虚点

出现环时 选择最大的bbb删去即可

/*
一些不成型的想法:贪心??怎么贪两个呢??——先让其中一维变成有序再着重贪另一维
私以为此题这样不可做 passkruskal重构树——最小生成树
最小生成树上的两点间距离最小LCT维护最小生成树
a精灵从小到大排序 插入b精灵??边权改成点权 构造虚点
*/
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 150005
#define inf 0x7f7f7f7f 
struct node {int u, v, a, b;
}edge[maxn];
struct LCT {int f, val, rev, id;int son[2];
}t[maxn];
int n, m, ans = inf;
int st[maxn], w[maxn];bool cmp( node x, node y ) {return ( x.a == y.a ) ? ( x.b < y.b ) : ( x.a < y.a );
}bool isroot( int x ) {return t[t[x].f].son[0] == x || t[t[x].f].son[1] == x;
}void pushup( int x ) {t[x].id = x, t[x].val = w[x];if( t[x].son[0] && t[t[x].son[0]].val > t[x].val ) {t[x].val = t[t[x].son[0]].val;t[x].id = t[t[x].son[0]].id;}if( t[x].son[1] && t[t[x].son[1]].val > t[x].val ) {t[x].val = t[t[x].son[1]].val;t[x].id = t[t[x].son[1]].id;}
}void rotate( int x ) {int fa = t[x].f, Gfa = t[fa].f, k = t[fa].son[1] == x;if( isroot( fa ) ) t[Gfa].son[t[Gfa].son[1] == fa] = x;t[x].f = Gfa;if( t[x].son[k ^ 1] ) t[t[x].son[k ^ 1]].f = fa;t[fa].son[k] = t[x].son[k ^ 1];t[x].son[k ^ 1] = fa;t[fa].f = x;pushup( fa );pushup( x );
}void pushdown( int x ) {if( t[x].rev ) {swap( t[x].son[0], t[x].son[1] );if( t[x].son[0] ) t[t[x].son[0]].rev ^= 1;if( t[x].son[1] ) t[t[x].son[1]].rev ^= 1;t[x].rev = 0;}
}void splay( int x ) {int top = 0, y = x;st[++ top] = y;while( isroot( y ) ) st[++ top] = y = t[y].f;while( top ) pushdown( st[top --] );while( isroot( x ) ) {int fa = t[x].f, Gfa = t[fa].f;if( isroot( fa ) ) ( ( t[Gfa].son[0] == fa ) ^ ( t[fa].son[0] == x ) ) ? rotate( x ) : rotate( fa );rotate( x );}
}void access( int x ) {for( int son = 0;x;son = x, x = t[x].f ) {splay( x );t[x].son[1] = son;pushup( x );}
}int FindRoot( int x ) {access( x );splay( x );while( t[x].son[0] ) {pushdown( x );x = t[x].son[0];}return x;
}void MakeRoot( int x ) {access( x );splay( x );t[x].rev ^= 1;pushdown( x );
}void link( int x, int y ) {MakeRoot( x );if( FindRoot( y ) != x ) t[x].f = y;
}void split( int x, int y ) {MakeRoot( x );access( y );splay( y );
}
bool Union( int x, int y ) {MakeRoot( x );return FindRoot( y ) == x;
}int main() {scanf( "%d %d", &n, &m );for( int i = 1;i <= m;i ++ )scanf( "%d %d %d %d", &edge[i].u, &edge[i].v, &edge[i].a, &edge[i].b );sort( edge + 1, edge + m + 1, cmp );for( int i = 1;i <= m;i ++ ) {w[i + n] = edge[i].b;int u = edge[i].u, v = edge[i].v;if( u == v ) continue;if( Union( u, v ) ) {split( u, v );if( t[v].val <= edge[i].b ) continue;int x = t[v].id;splay( x );t[t[x].son[0]].f = t[t[x].son[1]].f = 0;link( u, i + n ), link( i + n, v );}elselink( u, i + n ), link( i + n, v );if( Union( 1, n ) ) split( 1, n ), ans = min( ans, edge[i].a + t[n].val );}if( ans == inf ) printf( "-1\n" );else printf( "%d\n", ans );return 0;
}

[ZJOI2018]历史

题目

一句话题意: 给出一棵树,给定每一个点的accessaccessaccess次数,计算轻重链切换次数的最大值,带修改

先不考虑带修改的问题

uuu,只有在uuu子树里的点进行accessaccessaccess才会影响答案,并且点独立,可以分开算

假设uuu的子树发生了两次accessaccessaccess,当且仅当这两次操作的点分属于uuu两个不同儿子的子树中,答案才会+1+1+1

要使答案最大,就是尽量让所有相邻发生的崛起都来自不同子树

相当于有[0,m][0,m][0,m]种颜色,每种颜色有aia_iai个,最大化相邻颜色不同的个数

tot=∑i=0mai,maxx=maxi=0m{ai}tot=\sum_{i=0}^ma_i,maxx=max_{i=0}^m\{a_i\}tot=i=0mai,maxx=maxi=0m{ai}

答案则为min{t−1,2×(tot−maxx)}min\{t-1,2\times (tot-maxx)\}min{t1,2×(totmaxx)}

考虑先放最多的maxxmaxxmaxx个然后插空,对于剩下的pos=tot−maxxpos=tot-maxxpos=totmaxx

如果pos≤maxx−1pos\le maxx-1posmaxx1,显然直接插空,贡献2×p2\times p2×p

如果pos>maxx−1pos>maxx-1pos>maxx1,一定可以通过不断来回插空,达到上界tot−1tot-1tot1

O(n)O(n)O(n)的时间搜一遍整棵树即可

现在加上修改

根据2×maxx≥tot+12\times maxx\ge tot+12×maxxtot+1这个分界线处理

为什么这个是分界线??当满足这个式子的时候,答案一定取后者2×(tot−maxx)2\times (tot-maxx)2×(totmaxx)

optiopt_iopti表示iii子树的操作次数和,如果满足2×opti≥optfai+12\times opt_i\ge opt_{fa_i}+12×optioptfai+1,就把i→fai\rightarrow faifa连为实边,否则为虚边

为什么这么定义??因为在这样的定义下,如果iii子树内操作jjj加上权值www,其只会影响jjj到根路径上的点的答案和虚边关系

因为对于实边,存在2(opti+w)≥(optfai+w)+12(opt_i+w)\ge (opt_{fa_i}+w)+12(opti+w)(optfai+w)+1,即实边还是实边

并且答案Δ=2[(optfai+w)−(opti+w)]−2[optfai−opti]=0\Delta =2[(opt_{fa_i}+w)-(opt_i+w)]-2[opt_{fa_i}-opt_i]=0Δ=2[(optfai+w)(opti+w)]2[optfaiopti]=0 是不变的

对于怎么找到路径上的虚边,就写LCTLCTLCT,因为这里的操作是类似于accessaccessaccess的,只不过要判断一下虚实边之间的变换

ansansans减去点更新前的答案再加上更新后的答案即可

#include <cstdio>
#include <vector>
using namespace std;
#define int long long
#define maxn 400005
struct node {int fa, val, sum, thin_edge_sum;int son[2];
}t[maxn];
vector < int > G[maxn];
int n, m, ans;bool isroot( int x ) {return t[t[x].fa].son[0] == x || t[t[x].fa].son[1] == x;
}void pushup( int x ) {t[x].sum = t[x].val + t[t[x].son[0]].sum + t[t[x].son[1]].sum + t[x].thin_edge_sum;
} void rotate( int x ) {int fa = t[x].fa, Gfa = t[fa].fa, k = t[fa].son[1] == x;if( isroot( fa ) ) t[Gfa].son[t[Gfa].son[1] == fa] = x;t[x].fa = Gfa;if( t[x].son[k ^ 1] ) t[t[x].son[k ^ 1]].fa = fa;t[fa].son[k] = t[x].son[k ^ 1];t[x].son[k ^ 1] = fa;t[fa].fa = x;pushup( fa );pushup( x );
}void splay( int x ) {while( isroot( x ) ) {int fa = t[x].fa, Gfa = t[fa].fa;if( isroot( fa ) )( ( t[Gfa].son[1] == fa ) ^ ( t[fa].son[1] == x ) ) ? rotate( fa ): rotate( x );rotate( x );}
}int calc( int x, int tot, int maxx ) {if( t[x].son[1] ) return ( tot - maxx ) * 2;else if( t[x].val * 2 > tot ) return ( tot - t[x].val ) * 2;else return tot - 1;
}void modify( int x, int w ) {splay( x );/*如果想要得到某一个点的tot就应该计算splay里面深度≥它的点的val之和也就是将这个点splay到根后这个点的val加上其右子树的val和*/int tot = t[x].sum - t[t[x].son[0]].sum;int maxx = t[t[x].son[1]].sum;ans -= calc( x, tot, maxx );t[x].val += w, tot += w, t[x].sum += w;if( maxx * 2 < tot + 1 ) { //实边变虚边t[x].thin_edge_sum += maxx;t[x].son[1] = 0;}ans += calc( x, tot, maxx );pushup( x );int son;for( x = t[son = x].fa;x;x = t[son = x].fa ) {splay( x );int tot = t[x].sum - t[t[x].son[0]].sum;int maxx = t[t[x].son[1]].sum;ans -= calc( x, tot, maxx );t[x].thin_edge_sum += w, tot += w, t[x].sum += w;if( maxx * 2 < tot + 1 ) {t[x].thin_edge_sum += maxx;t[x].son[1] = 0;maxx = 0;}if( t[son].sum * 2 > tot ) {t[x].thin_edge_sum -= t[son].sum;t[x].son[1] = son;maxx = t[son].sum;}ans += calc( x, tot, maxx );pushup( x );}
}void dfs( int u ) {t[u].sum = t[u].val;int pos = 0, maxx = t[u].val;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == t[u].fa ) continue;t[v].fa = u;dfs( v );t[u].sum += t[v].sum;if( t[v].sum > maxx ) maxx = t[v].sum, pos = v;}ans += min( t[u].sum - 1, ( t[u].sum - maxx ) * 2 );if( maxx * 2 >= t[u].sum + 1 ) t[u].son[1] = pos; //实边 修改是不会更改贡献的t[u].thin_edge_sum = t[u].sum - t[u].val - t[t[u].son[1]].sum;//所有虚边的操作数和 以后是会更改贡献的
}signed main() {scanf( "%lld %lld", &n, &m );for( int i = 1;i <= n;i ++ )scanf( "%lld", &t[i].val );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%lld %lld", &u, &v );G[u].push_back( v );G[v].push_back( u );  }dfs( 1 );printf( "%lld\n", ans );for( int i = 1, x, y;i <= m;i ++ ) {scanf( "%lld %lld", &x, &y );modify( x, y );printf( "%lld\n", ans );}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317524.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《小团队构建大网站:中小研发团队架构实践》送书活动结果公布

截止到1月25日24&#xff1a;00&#xff0c;本次送书活动共收到75位同学参与回复&#xff0c;本次很多同学在看到活动的书十年IT老兵带你通过案例学架构&#xff0c;附C#代码&#xff0c;自行就到各大网络商店上购买了书&#xff0c;据反馈这个书很不错.下面把Top 2的留言截图给…

P6466-分散层叠算法(Fractional Cascading)【模板】

正题 题目链接:https://www.luogu.com.cn/problem/P6466 题目大意 给出kkk个长度为nnn的有序序列&#xff0c;qqq次询问给出xxx&#xff0c;求所有序列中xxx的后继的异或和。 强制在线 1≤k≤100,1≤n≤104,1≤q≤51051\leq k\leq 100,1\leq n\leq 10^4,1\leq q\leq 5\times…

11.13模拟:总结

文章目录总结题目update&#xff08;solution of T3&#xff09;&#xff1a;代码230pts100100300总结 不要先入为主&#xff01;如果某种算法受阻&#xff0c;要尝试一下别的路子&#xff01;&#xff01; 本次的主要问题&#xff1a; T2花费时间略长&#xff08;指2h&#…

Strategic game(树的最小点覆盖)

Strategic game 题意&#xff1a; 一个树&#xff0c;在一个节点放兵&#xff0c;周围的边就被守护&#xff0c;守护所有的边&#xff0c;问最少放多少兵 题解&#xff1a; 这种问题又称树的最小点覆盖 dp[x][1]以x为根的子树全被看住且在x上放置士兵的最少所需的士兵数量 …

test6 3-21 2021省选模拟赛six

文章目录考试复盘rnglgpm考试复盘 第一题&#xff0c;乍一看期望&#xff0c;又不会做了&#xff0c;乍二看&#xff0c;暴力好像可以202020跑路&#xff0c;屁颠屁颠敲完死活过不了这个简单的样例&#xff1b;开始(⊙⊙?)乍三看&#xff0c;实数&#xff1f;&#xff1f;完了…

如何为 .NET Core CLI 启用 TAB 自动补全功能

Intro在 Linux 下经常可以发现有些目录/文件名&#xff0c;以及有些工具可以命令输入几个字母之后按 TAB 自动补全&#xff0c;最近发现其实 dotnet cli 也可以&#xff0c;从.NET Core 2.0 SDK 开始&#xff0c;NET Core CLI 支持 tab 自动补全。你如果已经装了 dotnet Core S…

P8215-[THUPC2022 初赛]分组作业【网络流】

正题 题目链接:https://www.luogu.com.cn/problem/P8215 题目大意 有2n2\times n2n个人&#xff0c;第2i−12\times i-12i−1和第2i2\times i2i个人一组&#xff0c;然后每个人可以选择愿不愿意合作&#xff0c;愿意需要付出cic_ici​代价&#xff0c;不愿意是did_idi​代价&…

.NET IdentityServer4实战-开篇介绍与规划

一.开篇寄语由于假期的无聊&#xff0c;我决定了一个非常有挑战性的活动&#xff0c;也就是在年假给大家带来一个基于OAuth 2.0的身份授权框架&#xff0c;它就是 IdentityServer4 &#xff0c;如果没有意外的话&#xff0c;一定可以顺利的写完的&#xff0c;如果两天写一篇的话…

CF1408G:Clusterization Counting(区间dp、克鲁斯卡尔重构树)

解析 很妙的一道题 看这两个南辕北辙的标签就知道这题不简单 看见dp思路还是得打开 一开始其实想到按边权排序了 但卡在了重构树上 遇到dp一定要敢想 勇于和图论等结合 考虑正解 按照边权升序排序 依次加边到图中 并查集维护连通性和集合内的边数 发现&#xff0c;一个联通块…

test5 3-20 2021省选模拟赛five

考试复盘 第一题&#xff1f;&#xff1f;是个什么互动哦&#xff0c;直接乱来的(&#xffe3;&#xffe3;)σ…(&#xff3f;&#xff3f;)ノ&#xff5c;壁 第二题是前几天考过的&#xff0c;所以知道是polyapolyapolya&#xff0c;但是式子推到最后的二项式定理没推对&am…

Cell Phone Network

Cell Phone Network 题意: 每个牧场的电塔可以覆盖与该牧场相邻的电塔&#xff0c;为了让所有牛都可以打电话&#xff0c;求建的电塔的最小数量 题解&#xff1a; 树的最小支配集 dp[x][0]&#xff1a;选点i&#xff0c;并且以点i为根的子树都被覆盖 dp[x][1]&#xff1a;不…

P8207-[THUPC2022 初赛]最小公倍树【Kruskal】

正题 题目链接:https://www.luogu.com.cn/problem/P8207 题目大意 有编号为[L,R][L,R][L,R]区间的点&#xff0c;连接两个点x,yx,yx,y边权的为LCM(x,y)LCM(x,y)LCM(x,y)&#xff0c;求这张图的最小生成树。 1≤L≤R≤106,R−L≤1051\leq L\leq R\leq 10^6,R-L\leq 10^51≤L≤…

微信小程序开发必看,《使用 .NET Core + DevOps 开发微信跨平台应用》,苏州.NET俱乐部课程分享...

【课程名称】《使用 .NET Core DevOps 开发微信跨平台应用》【老师介绍】苏震巍&#xff0c;苏州盛派网络CEO&#xff0c;微软最有价值专家&#xff08;MVP&#xff09;、微软 Ignite 技术大会讲师&#xff0c;Senparc.Weixin作者&#xff0c;《微信开发深度解析》等书作者。苏…

11.14 模拟:总结

update 等出分挂大分再回来打脸 一语成谶了属于是 给自己测了一下 《很棒》 真就挂了大分 实际得分&#xff1a; 00020 T1和T3都挂没了 qwq T1是因为两个背包的定义是不一样的&#xff01; 我应该做两个背包分别跑就好了 T3全部MLE… 我最后十分钟想贪一个T3的第五个点 然后…

P8208-[THUPC2022 初赛]骰子旅行【dp】

正题 题目链接:https://www.luogu.com.cn/problem/P8208 题目大意 给出nnn个点若干条边的一张图中&#xff0c;一个人在111开始随机游走ttt步。 如果他到达一个点他曾经到达过的点&#xff0c;那么就会产生它上次在这个点走向的点的编号的贡献。 求期望贡献。 1≤n≤100,1≤…

Axial symmetry FZU - 2035

Axial symmetry FZU - 2035 题意&#xff1a; 给一个多边形&#xff0c;边平行于x轴或者y&#xff0c;问是否存在对称轴 题解&#xff1a; 将每个点的坐标&#xff0c;以及每个边的中点的坐标&#xff0c;按照顺时针顺序存入&#xff0c;多边形的对称轴一定穿过对应两个点&…

test 7 3-22 2021省选模拟赛seven

文章目录考试复盘人生赢家黑红兔考试复盘 T1T1T1 subtask1:n≤5subtask1:n\le 5subtask1:n≤5&#xff0c;暴搜点的颜色状态以及边的存在状态 对于一条连接相同颜色点的边&#xff0c;可要可不要&#xff0c;不会提供形态变化的贡献&#xff0c;2edge2^{edge}2edge dpdpdp&…

Shadow Properties之美(一)【Microsoft Entity Framework Core随笔】

最近在做公司的项目的时候&#xff0c;开始把部分程序迁移到EF Core&#xff0c;然后有了一些感触&#xff0c;趁着还没忘却&#xff0c;还是先记录下来。EF Core还在成长中&#xff0c;我写这个的时候&#xff0c;版本是2.2。如果对着已有的EF 5/6来说&#xff0c;还有很多功能…

CF1413C Perform Easily(two pointers)

解析 巧夺天工 可以说是把two pointers玩明白了 把所有的可能减出来的结果升序排列一下 然后一个选取区间合法当且仅当这个区间含有1-n所有数的至少一个可能的差 然后就可以two pointers了 #include<bits/stdc.h> const int N2e5100; const int mod1e97; #define ll lon…

CF1039E-Summer Oenothera Exhibition【LCT,根号分治】

正题 题目链接:https://www.luogu.com.cn/problem/CF1039E 题目大意 给出nnn个数的序列&#xff0c;mmm次询问至少将这个序列分成多少段才能满足每一段的和不超过w−qiw-q_iw−qi​。 1≤n,m≤105,1≤w,ai≤1091\leq n,m\leq 10^5,1\leq w,a_i\leq 10^91≤n,m≤105,1≤w,ai​…