这道题首先可以看出答案一定是一条边,而且答案一定在最小生成树上,那么我们就可以在这个最小生成树上维护他与异色儿子的边最小值,所以我们就可以已通过Kruskal和一棵平衡树来解决,时间复杂度是O(n*logn)级别的但是那个大常数..........然后在最外面独立一棵权值线段树来存最终答案.....

证明:若答案不是一条边,那么在这个答案里一定有中间点可以推翻答案;若答案不是在最小生成树内,那么在最小生成树上一定用答案可以更新他(这个答案边与最小生成树内这两个点的路径形成回路,那么他一定会被推翻)(最小生成树外的边与最小生成树形成回路,那个路径一定比回路内其它边大(或等),会被其它边替代)

一定要注意当查询时替罪羊的中间点可以生效时当且仅当,他在区间内并且他存在。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<algorithm>
#define MAXN 200005
#define Inf 1000000
using namespace std;
double alpha=0.756;
inline int read()
{
int sum=;
char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')
{
sum=(sum<<)+(sum<<)+ch-;
ch=getchar();
}
return sum;
}
int sz;
struct Seg_Tree
{
Seg_Tree *ch[];
int l,r,mid,size;
}node[Inf<<],*seg;
inline Seg_Tree *New(int l,int r)
{
Seg_Tree *p=&node[++sz];
p->l=l;
p->r=r;
p->mid=(l+r)>>;
p->size=;
return p;
}
inline int Min(int x,int y)
{
return x<y?x:y;
}
struct ScapeGoat_Tree
{
ScapeGoat_Tree *ch[],*f;
int key,size,col,ex,cover,min;
void pushup()
{
size=ch[]->size+ex+ch[]->size;
cover=ch[]->cover++ch[]->cover;
min=Min(ch[]->min,ch[]->min);
if(ex)min=Min(key,min);
}
bool bad()
{
return cover*alpha+<ch[]->cover||cover*alpha+<ch[]->size;
}
}mempool[MAXN<<],*list[MAXN<<],*stack[MAXN<<],*null,*root[MAXN],*pos[MAXN];
int len,top;
inline void pre()
{
null=mempool;
for(int i=;i<(MAXN<<);i++)stack[++top]=mempool+i;
null->ch[]=null->ch[]=null->f=null;
null->key=null->min=0x7fffffff;
for(int i=;i<MAXN;i++)root[i]=null;
}
inline ScapeGoat_Tree *New(int key,ScapeGoat_Tree *fa,int co)
{
ScapeGoat_Tree *p=stack[top--];
p->ch[]=p->ch[]=null;
p->min=p->key=key;
p->f=fa;
p->col=co;
p->size=p->cover=p->ex=;
return p;
}
struct Tr
{
int to,next,w;
}C[MAXN<<];
int Head[MAXN],T;
inline void Add(int x,int y,int z)
{
C[++T].to=y;
C[T].next=Head[x];
Head[x]=T;
C[T].w=z;
}
int col[MAXN],Ans[MAXN];
struct E
{
int x,y,z;
}e[MAXN];
int n,m,k,q;
int Fa[MAXN];
int comp(const E a,const E b)
{
return a.z<b.z;
}
int f[MAXN];
int find(int x)
{
return Fa[x]==x?x:(Fa[x]=find(Fa[x]));
}
inline void unit(int x,int y)
{
if(x!=y)Fa[x]=y;
}
inline void Kruskal()
{
sort(e+,e+m+,comp);
for(int i=;i<=n;i++)
Fa[i]=i;
int had=;
for(int i=;i<=m;i++)
if(find(e[i].x)!=find(e[i].y))
{
Add(e[i].x,e[i].y,e[i].z);
Add(e[i].y,e[i].x,e[i].z);
unit(find(e[i].x),find(e[i].y));
had++;
if(had==n)break;
}
}
ScapeGoat_Tree **insert(int key,int co,ScapeGoat_Tree *&p,int id,ScapeGoat_Tree *fa)
{
if(p==null)
{
p=New(key,fa,co);
pos[id]=p;
return &null;
}
ScapeGoat_Tree **ret=insert(key,co,p->ch[p->col<=co],id,p);
if(p->bad())ret=&p;
p->pushup();
return ret;
}
void travel(ScapeGoat_Tree *p)
{
if(p==null)return;
travel(p->ch[]);
if(p->ex)list[++len]=p;
else stack[++top]=p;
travel(p->ch[]);
}
ScapeGoat_Tree *divide(int l,int r,ScapeGoat_Tree *fa)
{
if(l>r)return null;
int mid=(l+r)>>;
list[mid]->ch[]=divide(l,mid-,list[mid]);
list[mid]->ch[]=divide(mid+,r,list[mid]);
list[mid]->f=fa;
list[mid]->pushup();
return list[mid];
}
inline void rebuild(ScapeGoat_Tree *&p)
{
len=;
ScapeGoat_Tree *fa=p->f;
travel(p);
p=divide(,len,fa);
}
inline void Insert(int key,int co,ScapeGoat_Tree *&Root,int id)
{
ScapeGoat_Tree **p=insert(key,co,Root,id,null);
if(*p!=null)rebuild(*p);
}
void dfs(int x)
{
for(int i=Head[x];i;i=C[i].next)
if(C[i].to!=f[x])
{
f[C[i].to]=x;
Insert(C[i].w,col[C[i].to],root[x],C[i].to);
dfs(C[i].to);
}
}
void build(Seg_Tree *p)
{
if(p->l==p->r)return;
p->ch[]=New(p->l,p->mid);
p->ch[]=New(p->mid+,p->r);
build(p->ch[]);
build(p->ch[]);
}
inline int Rank(int co,ScapeGoat_Tree *Root)
{
ScapeGoat_Tree *p=Root;
int ret=;
while(p!=null)
if(p->col>=co)
p=p->ch[];
else
ret+=p->ch[]->size+p->ex,p=p->ch[];
return ret;
}
int query(ScapeGoat_Tree *p,int l,int r)
{
if(l>r)return 0x7fffffff;
if(p==null)return 0x7fffffff;
if(l<=&&r>=p->size)
return p->min;
int ans=0x7fffffff;
if(p->ex&&l<=p->ch[]->size+p->ex&&r>=p->ch[]->size+p->ex)
ans=p->key;
if(l<=p->ch[]->size)
ans=Min(ans,query(p->ch[],l,r));
if(r>p->ch[]->size+p->ex)
ans=Min(ans,query(p->ch[],l-(p->ch[]->size+p->ex),r-(p->ch[]->size+p->ex)));
return ans;
}
inline int Query(int x)
{
int l=Rank(col[x],root[x]);
int ans=query(root[x],,l);
int r=Rank(col[x]+,root[x])+;
ans=Min(ans,query(root[x],r,root[x]->size));
return ans;
}
void update(Seg_Tree *p,int key)
{
if(key>Inf)return;
p->size++;
if(p->l==p->r)return;
update(p->ch[p->mid<key],key);
}
inline void Init()
{
n=read(),m=read(),k=read(),q=read();
for(int i=;i<=m;i++)
e[i].x=read(),e[i].y=read(),e[i].z=read();
Kruskal();
for(int i=;i<=n;i++)col[i]=read();
dfs();
seg=New(,Inf);
build(seg);
for(int i=;i<=n;i++)
update(seg,(Ans[i]=Query(i)));
}
inline void Del(int x)
{
pos[x]->ex=;
ScapeGoat_Tree *p=pos[x];
while(p!=null)
p->pushup(),p=p->f;
}
void del(Seg_Tree *p,int key)
{
if(key>Inf)return;
p->size--;
if(p->l==p->r)return;
del(p->ch[p->mid<key],key);
}
int get_ans(Seg_Tree *p)
{
if(p->l==p->r)return p->mid;
if(p->ch[]->size)return get_ans(p->ch[]);
else return get_ans(p->ch[]);
}
inline void work()
{
while(q--)
{
int x=read(),y=read();
if(x!=)Del(x);
if(x!=)if(root[f[x]]->bad())rebuild(root[f[x]]);
col[x]=y;
if(x!=)Insert(pos[x]->key,y,root[f[x]],x);
del(seg,Ans[x]);
if(x!=)del(seg,Ans[f[x]]);
update(seg,(Ans[x]=Query(x)));
if(x!=)update(seg,(Ans[f[x]]=Query(f[x])));
printf("%d\n",get_ans(seg));
}
}
int main()
{
pre();
Init();
work();
return ;
}

BZOJ 4777 Usaco2017 Open Switch Grass Kruskal+替罪羊树+权值线段树的更多相关文章

  1. [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)

    [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...

  2. BZOJ 4777: [Usaco2017 Open]Switch Grass

    4777: [Usaco2017 Open]Switch Grass Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 46  Solved: 10[Su ...

  3. 【BZOJ3065】带插入区间K小值 替罪羊树+权值线段树

    [BZOJ3065]带插入区间K小值 Description 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理 ...

  4. BZOJ 4605 崂山白花蛇草水(权值线段树+KD树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4605 [题目大意] 操作 1 x y k 表示在点(x,y)上放置k个物品, 操作 2 ...

  5. 【bzoj3065】带插入区间K小值 替罪羊树套权值线段树

    题目描述 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间k小值.他每次向它的随从伏特提出 ...

  6. bzoj 2733: [HNOI2012]永无乡【并查集+权值线段树】

    bzoj上数组开大会T-- 本来想用set瞎搞的,想了想发现不行 总之就是并查集,每个点开一个动态开点的权值线段树,然后合并的时候把值并在根上,询问的时候找出在根的线段树里找出k小值,看看这个值属于哪 ...

  7. 3065: 带插入区间K小值_树套树_替罪羊树_权值线段树

    经过周六一天,周一3个小时的晚自习,周二2个小时的疯狂debug,终于凭借自己切掉了这道树套树题. Code: #include <cstdio> #include <algorit ...

  8. [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)

    [BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...

  9. BZOJ4777 [Usaco2017 Open]Switch Grass[最小生成树+权值线段树套平衡树]

    标题解法是吓人的. 图上修改询问,不好用数据结构操作.尝试转化为树来维护.发现(不要问怎么发现的)最小生成树在这里比较行得通,因为最近异色点对一定是相邻的(很好想),所以只要看最短的一条两端连着异色点 ...

随机推荐

  1. 微信小程序中无刷新修改

    1.点击事件无刷新修改 原理:onload事件中是把这个分类和品牌的列表全部拿出来,拼接成数组的格式,在小程序中遍历的时候就要把小标(index)给绑定到左侧的品牌上,然后js中获取index的值,就 ...

  2. ELK 安装部署实战 (最新6.4.0版本)

    一.实战背景 根据公司平台的发展速度,对于ELK日志分析日益迫切.主要的需求有: 1.用户行为分析 2.运营活动点击率分析 作为上述2点需求,安装最新版本6.4.0是非常有必要的,大家可根据本人之前博 ...

  3. Python全栈day 02

    Python全栈day 02 一.循环语句 while 用法 num = 1 while num <= 10: print(num) num += 1 # 循环打印输出1-10 while el ...

  4. PAT-B java实现

    注意:java提交PAT时,不需要加package : 类名必须是Main. 1001 害死人不偿命的(3n+1)猜想 (15) 输入格式:每个测试输入包含1个测试用例,即给出自然数n的值. 输出格式 ...

  5. stm32+lwip(四):网页服务器测试

    我是卓波,很高兴你来看我的博客. 系列文章: stm32+lwip(一):使用STM32CubeMX生成项目 stm32+lwip(二):UDP测试 stm32+lwip(三):TCP测试 stm32 ...

  6. 38-JWT 设计解析及定制

    可去官网下载Security项目查看源码 只需修改 AddJwtBearer中的行为即可 public void ConfigureServices(IServiceCollection servic ...

  7. Zookeeper系列(二) Zookeeper配置说明

            在配置ZooKeeper配置文件时,有些参数是必需的,有些参数是可选的,这些必需的参数构成了Zookeeper配置文件的最低配置要求,如果需要对ZooKeeper进行更详细的配置,可以 ...

  8. struts2官方 中文教程 系列十三:利用通配符选择方法

    介绍 在本教程中,我们将介绍如何在struts.xml中配置action节点以达到仅使用一个action节点将几个不同的url关联到特定action类的特定方法.这样做的目的是减少struts.xml ...

  9. 插件开发遇到的坑------final 型变量,编译过程被优化

    android 插件开发遇到的坑 今天遇到一个坑,pdf 插件,调用了主工程的一个静态final 字符串,但是主工程里面已经没有这个字符串了,却没有崩溃. 后来同事说,因为字符串可能已经直接被写死了. ...

  10. 前端学习webpack

    ### 模块化- 为了保证代码充分解耦,一个大的项目拆分成互相依赖的一个一个的小的模块,最后再通过简单的方式合并在一起- 每一个js文件都可以看成一个单独的模块在node这边(服务器端),提出Comm ...