题目

题目大意

有一堆点,每个点都有其权值\(c_i\)。

每次插入边\((u,v)\),\(u\)和\(1\)连通,\(v\)和\(1\)不连通。最后保证形成一棵树。

每次插入的时候询问\(1\)到\(u\)的路径上逆序对的个数。然后将\(1\)到\(u\)的路径上的所有节点的权值设为\(c_v\).


思考历程

一看就知道是什么数据结构题了……

然而刚了很久都不知道怎么做……

于是就直接打暴力。暴力跳\(fa\),用树状数组计算逆序对的个数。

后来还有点时间,于是看准了\(c_i\leq 2\)的数据。

于是打了个树链剖分加线段树来维护。线段树上每个区间维护的是个大小为\(3\)的桶和答案,区间合并的时候就是左右两边的答案加上左边权值大于右边的个数。

打完了之后急着去吃饭,完全没有调过……

后来发现这个树链剖分没有分……倒是覆盖了我的暴力……原来暴力是可以吃掉\(c_i\leq 2\)的数据的……


正解

看到正解的时候我也震惊了……

请用脑子模拟一下操作的画面。

然后试着跟\(LCT\)建立联系。

于是我们就发现这个操作过程与\(LCT\)神似!

每个\(splay\)维护权值相同的一条链,修改的时候相当于\(access\)上去……

将它到祖先的路径全部变成同一个权值。

我们也知道\(LCT\)的时间复杂度是均摊\(\lg n\)的。虽然不会证明。

那么我们可以理解成出现过的颜色相同的段数是\(O(n\lg n)\)级别的。

询问的时候用树状数组来维护。模拟\(access\)的过程就可以了。

于是这题就非常轻松地AC了。而且由于这题完全不需要\(mroot\)操作,所以也不用翻转……

\(LCT\)短得跟树链剖分差不多……


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
int n;
int c[N],maxc;
int *p[N];
inline bool cmpp(int *x,int *y){
return *x<*y;
}
int t[N];
#define lowbit(x) ((x)&(-(x)))
inline void add(int x,int c){
for (;x<=maxc;x+=lowbit(x))
t[x]+=c;
}
inline int query(int x){
int res=0;
for (;x;x-=lowbit(x))
res+=t[x];
return res;
}
inline void clear(int x){
for (;x<=maxc && t[x];x+=lowbit(x))
t[x]=0;
}
struct Node{
Node *fa,*c[2];
int is_root;
int siz;
inline void update(){siz=c[0]->siz+c[1]->siz+1;}
inline bool getson(){return fa->c[0]!=this;}
inline void rotate(){
Node *y=fa,*z=y->fa;
if (y->is_root){
is_root=y->is_root;
y->is_root=0;
}
else
z->c[y->getson()]=this;
int k=getson();
fa=z;
y->c[k]=c[k^1];
c[k^1]->fa=y;
c[k^1]=y;
y->fa=this;
siz=y->siz,y->update();
}
inline void splay(){
while (!is_root){
if (!fa->is_root){
if (getson()!=fa->getson())
rotate();
else
fa->rotate();
}
rotate();
}
}
} d[N],*null;
int main(){
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;++i)
scanf("%d",&c[i]),p[i]=&c[i];
sort(p+1,p+n+1,cmpp);
for (int i=1,last=-1;i<=n;++i){
if (*p[i]!=last){
maxc++;
last=*p[i];
}
*p[i]=maxc;
}
null=d;
*null={null,null,null,0,0};
for (int i=1;i<=n;++i)
d[i]={null,null,null,c[i],1};
for (int i=1;i<n;++i){
int u,v;
scanf("%d%d",&u,&v);
Node *x,*y;
long long ans=0;
for (x=&d[u];x!=null;x=x->fa){
x->splay();
ans+=(long long)query(x->is_root-1)*(x->c[0]->siz+1);
add(x->is_root,x->c[0]->siz+1);
}
printf("%lld\n",ans);
d[v].fa=&d[u];
for (x=&d[v],y=null;x!=null;y=x,x=x->fa){
x->splay();
clear(x->is_root);
x->c[1]->is_root=x->is_root;
x->c[1]=y;
y->is_root=0;
x->update();
}
y->is_root=c[v];
}
return 0;
}

思考历程

在分析复杂度的时候,可以试着结合自己学过的数据结构……

[JZOJ6257] 【省选模拟8.9】修路的更多相关文章

  1. 【洛谷比赛】[LnOI2019]长脖子鹿省选模拟赛 T1 题解

    今天是[LnOI2019]长脖子鹿省选模拟赛的时间,小编表示考的不怎么样,改了半天也只会改第一题,那也先呈上题解吧. T1:P5248 [LnOI2019SP]快速多项式变换(FPT) 一看这题就很手 ...

  2. 省选模拟赛第四轮 B——O(n^4)->O(n^3)->O(n^2)

    一 稍微转化一下,就是找所有和原树差距不超过k的不同构树的个数 一个挺trick的想法是: 由于矩阵树定理的行列式的值是把邻接矩阵数值看做边权的图的所有生成树的边权乘积之和 那么如果把不存在于原树中的 ...

  3. NOI2019省选模拟赛 第五场

    爆炸了QAQ 传送门 \(A\) \(Mas\)的童年 这题我怎么感觉好像做过--我记得那个时候还因为没有取\(min\)结果\(100\to 0\)-- 因为是个异或我们肯定得按位考虑贡献了 把\( ...

  4. NOI2019省选模拟赛 第六场

    传送门 又炸了-- \(A\) 唐时月夜 不知道改了什么东西之后就\(A\)掉了\(.jpg\) 首先,题目保证"如果一片子水域曾经被操作过,那么在之后的施法中,这片子水域也一定会被操作&q ...

  5. 省选模拟赛 arg

    1 arg (arg.cpp/in/out, 1s, 512MB)1.1 Description给出一个长度为 m 的序列 A, 请你求出有多少种 1...n 的排列, 满足 A 是它的一个 LIS. ...

  6. 【NOI省选模拟】小奇的花园

    「题目背景」 小奇在家中的花园漫步时,总是会思考一些奇怪的问题. 「问题描述」 小奇的花园有n个温室,标号为1到n,温室以及以及温室间的双向道路形成一棵树. 每个温室都种植着一种花,随着季节的变换,温 ...

  7. @省选模拟赛03/16 - T3@ 超级树

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 一棵 k-超级树(k-SuperTree) 可按如下方法得到:取 ...

  8. 5.10 省选模拟赛 拍卖 博弈 dp

    LINK:拍卖 比赛的时候 前面时间浪费的有点多 写这道题的时候 没剩多少时间了. 随便设了一个状态 就开始做了. 果然需要认真的思考.其实 从我的状态的状态转移中可以看出所有的结论. 这里 就不再赘 ...

  9. 5.5 省选模拟赛 B Permutation 构造 贪心

    LINK:Permutation 对于这种构造神题 我自然是要补的.为啥就我没想出来哇. 30分还是很好写的 注意8!实际上很小 不需要爆搜 写bfs记录状态即可.至于判断状态是否出现与否 可以开ma ...

随机推荐

  1. java-day21

    # DQL:查询语句     1. 排序查询         * 语法:order by 子句             * order by 排序字段1 排序方式1 ,  排序字段2 排序方式2... ...

  2. 44-Ubuntu-用户管理-09-chmod的数字表示法介绍

    chmod 修改文件和目录权限 chmod在设置权限时,可以简单地使用三个数字分别对应拥有者/组和其他用户的权限. 注意: chmod直接修改文件|目录的'读|写|执行'权限,但是不能精确到拥有者|组 ...

  3. ForEach控制器

    ForEach一般是和用户定义的变量结合使用的 前面前缀一般是和用户定义的变量前缀一致 输出的变量是要使用的变量 这样能保证每次使用的变量不一样 add"_"before numb ...

  4. 结对编程UI

    GitHub:https://github.com/zsl1996/UI/commits/master 一.            实验内容 这是交付给最终用户的软件,有一定的界面和必要的辅助功能.完 ...

  5. JS window对象 History 对象 history对象记录了用户曾经浏览过的页面(URL),并可以实现浏览器前进与后退相似导航的功能。语法: window.history.[属性|方法]

    History 对象 history对象记录了用户曾经浏览过的页面(URL),并可以实现浏览器前进与后退相似导航的功能. 注意:从窗口被打开的那一刻开始记录,每个浏览器窗口.每个标签页乃至每个框架,都 ...

  6. leetcood学习笔记-110-平衡二叉树

    ---恢复内容开始--- 题目描述: 方法一: class Solution(object): def isBalanced(self, root): """ :type ...

  7. [原创]Delphi 字符串函数(字符串判断 TryStrToFloat 、TryStrToInt、TryStrToInt64、TryStrToBool、TryStrToCurr、TryStrToDate、TryStrToTime、TryStrToDateTime)

    引用单元SysUtils TryStrToFloat .TryStrToInt.TryStrToInt64.TryStrToBool.TryStrToCurr.TryStrToDate.TryStrT ...

  8. delphi xe10 获取屏幕截图

    //截取屏幕图片 function MakeScaleScreenshot(Sender: TControl): TBitmap; function GetScreenScale: Single; v ...

  9. BOM——特效

    特效 偏移量 offsetParent用于获取定位的父级元素 offsetParent和parentNode的区别  var box = document.getElementById('box'); ...

  10. MaxCompute表设计最佳实践

    MaxCompute表设计最佳实践 产生大量小文件的操作 MaxCompute表的小文件会影响存储和计算性能,因此我们先介绍下什么样的操作会产生大量小文件,从 而在做表设计的时候考虑避开此类操作. 使 ...