题目

题目大意

有一堆点,每个点都有其权值\(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;
}

思考历程

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

最新文章

  1. angular2系列教程(十一)路由嵌套、路由生命周期、matrix URL notation
  2. scikit-learn一般实例之四:使用管道和GridSearchCV选择降维
  3. python编程关键字
  4. Codeforces Round #161 (Div. 2) D. Cycle in Graph(无向图中找指定长度的简单环)
  5. Spring Collections XML 配置
  6. iOS 同一设备内的应用之间资源共享的实现
  7. Unity3D开发之NGUI点击事件穿透响应处理
  8. LeetCode-Largest Divisble Subset
  9. Maven项目pom文件设置JDK版本
  10. IDEA中显示RunDashboard
  11. Axure8破解码
  12. python 关于 input
  13. TCARS: Time- and Community-Aware Recommendation System(时间感知和社区感知推荐系统)
  14. Semana i 2018
  15. 黄聪:C#如何使用fiddlercoreCapture监控手机APP
  16. Mysql &amp; Hive 导入导出数据
  17. PHP接收IOS post过来的json数据无法解析的问题
  18. flush table with read lock的轻量级解决方案
  19. CentOS7.5安装Mysql5.7.22
  20. android 批量上传图片

热门文章

  1. .net 委托 +lamda表达式
  2. 移动端自动化测试appium 从入门到项目实战Python版✍✍✍
  3. async / await对异步的处理
  4. 框架集 frameset
  5. NX二次开发-UFUN创建倒角UF_MODL_create_chamfer
  6. Android获取Root权限之后的静默安装实现代码示例分析
  7. 修改ActiveProcessLinks链表隐藏进程
  8. elasticsearch配置文件
  9. jdk linux配置
  10. NodeJS学习笔记之Connect中间件模块(二)