BZOJ 4777 Usaco2017 Open Switch Grass Kruskal+替罪羊树+权值线段树

这道题首先可以看出答案一定是一条边,而且答案一定在最小生成树上,那么我们就可以在这个最小生成树上维护他与异色儿子的边最小值,所以我们就可以已通过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=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')
    {
        sum=(sum<<1)+(sum<<3)+ch-48;
        ch=getchar();
    }
    return sum;
}
int sz;
struct Seg_Tree
{
    Seg_Tree *ch[2];
    int l,r,mid,size;
}node[Inf<<2],*seg;
inline Seg_Tree *New(int l,int r)
{
    Seg_Tree *p=&node[++sz];
    p->l=l;
    p->r=r;
    p->mid=(l+r)>>1;
    p->size=0;
    return p;
}
inline int Min(int x,int y)
{
    return x<y?x:y;
}
struct ScapeGoat_Tree
{
    ScapeGoat_Tree *ch[2],*f;
    int key,size,col,ex,cover,min;
    void pushup()
    {
        size=ch[1]->size+ex+ch[0]->size;
        cover=ch[1]->cover+1+ch[0]->cover;
        min=Min(ch[0]->min,ch[1]->min);
        if(ex)min=Min(key,min);
    }
    bool bad()
    {
        return cover*alpha+5<ch[1]->cover||cover*alpha+5<ch[0]->size;
    }
}mempool[MAXN<<1],*list[MAXN<<1],*stack[MAXN<<1],*null,*root[MAXN],*pos[MAXN];
int len,top;
inline void pre()
{
   null=mempool;
   for(int i=1;i<(MAXN<<1);i++)stack[++top]=mempool+i;
   null->ch[0]=null->ch[1]=null->f=null;
   null->key=null->min=0x7fffffff;
   for(int i=1;i<MAXN;i++)root[i]=null;
}
inline ScapeGoat_Tree *New(int key,ScapeGoat_Tree *fa,int co)
{
    ScapeGoat_Tree *p=stack[top--];
    p->ch[1]=p->ch[0]=null;
    p->min=p->key=key;
    p->f=fa;
    p->col=co;
    p->size=p->cover=p->ex=1;
    return p;
}
struct Tr
{
    int to,next,w;
}C[MAXN<<1];
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+1,e+m+1,comp);
   for(int i=1;i<=n;i++)
    Fa[i]=i;
   int had=0;
   for(int i=1;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[0]);
    if(p->ex)list[++len]=p;
    else stack[++top]=p;
    travel(p->ch[1]);
}
ScapeGoat_Tree *divide(int l,int r,ScapeGoat_Tree *fa)
{
    if(l>r)return null;
    int mid=(l+r)>>1;
    list[mid]->ch[0]=divide(l,mid-1,list[mid]);
    list[mid]->ch[1]=divide(mid+1,r,list[mid]);
    list[mid]->f=fa;
    list[mid]->pushup();
    return list[mid];
}
inline void rebuild(ScapeGoat_Tree *&p)
{
    len=0;
    ScapeGoat_Tree *fa=p->f;
    travel(p);
    p=divide(1,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[0]=New(p->l,p->mid);
    p->ch[1]=New(p->mid+1,p->r);
    build(p->ch[0]);
    build(p->ch[1]);
}
inline int Rank(int co,ScapeGoat_Tree *Root)
{
    ScapeGoat_Tree *p=Root;
    int ret=0;
    while(p!=null)
     if(p->col>=co)
      p=p->ch[0];
     else
      ret+=p->ch[0]->size+p->ex,p=p->ch[1];
    return ret;
}
int query(ScapeGoat_Tree *p,int l,int r)
{
    if(l>r)return 0x7fffffff;
    if(p==null)return 0x7fffffff;
    if(l<=1&&r>=p->size)
     return p->min;
    int ans=0x7fffffff;
    if(p->ex&&l<=p->ch[0]->size+p->ex&&r>=p->ch[0]->size+p->ex)
     ans=p->key;
    if(l<=p->ch[0]->size)
     ans=Min(ans,query(p->ch[0],l,r));
    if(r>p->ch[0]->size+p->ex)
     ans=Min(ans,query(p->ch[1],l-(p->ch[0]->size+p->ex),r-(p->ch[0]->size+p->ex)));
    return ans;
}
inline int Query(int x)
{
    int l=Rank(col[x],root[x]);
    int ans=query(root[x],1,l);
    int r=Rank(col[x]+1,root[x])+1;
    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=1;i<=m;i++)
        e[i].x=read(),e[i].y=read(),e[i].z=read();
    Kruskal();
    for(int i=1;i<=n;i++)col[i]=read();
    dfs(1);
    seg=New(1,Inf);
    build(seg);
    for(int i=1;i<=n;i++)
     update(seg,(Ans[i]=Query(i)));
}
inline void Del(int x)
{
    pos[x]->ex=0;
    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[0]->size)return get_ans(p->ch[0]);
    else return get_ans(p->ch[1]);
}
inline void work()
{
  while(q--)
  {
     int x=read(),y=read();
     if(x!=1)Del(x);
     if(x!=1)if(root[f[x]]->bad())rebuild(root[f[x]]);
     col[x]=y;
     if(x!=1)Insert(pos[x]->key,y,root[f[x]],x);
     del(seg,Ans[x]);
     if(x!=1)del(seg,Ans[f[x]]);
     update(seg,(Ans[x]=Query(x)));
     if(x!=1)update(seg,(Ans[f[x]]=Query(f[x])));
     printf("%d\n",get_ans(seg));
  }
}
int main()
{
  pre();
  Init();
  work();
  return 0;
}

 

转载于:https://www.cnblogs.com/TSHugh/p/7152806.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
探索全栈前端技术的魅力:HTML+CSS+JS+JQ+Bootstrap网站源码深度解析 在这个数字化时代,构建一个既美观又功能强大的网站成为了许多开发者和企业追逐的目标。本份资源精心汇集了一套完整网站源码,融合了HTML的骨架搭建、CSS的视觉美化、JavaScript的交互逻辑、jQuery的高效操作以及Bootstrap的响应式设计,全方位揭秘了现代网页开发的精髓。 HTML,作为网页的基础,它构建了信息的框架;CSS则赋予网页生动的外观,让设计创意跃然屏上;JavaScript的加入,使网站拥有了灵动的交互体验;jQuery,作为JavaScript的强力辅助,简化了DOM操作与事件处理,让编码更为高效;而Bootstrap的融入,则确保了网站在不同设备上的完美呈现,响应式设计让访问无界限。 通过这份源码,你将: 学习如何高效组织HTML结构,提升页面加载速度与SEO友好度; 掌握CSS高级技巧,如Flexbox与Grid布局,打造适应各种屏幕的视觉盛宴; 理解JavaScript核心概念,动手实现动画、表单验证等动态效果; 利用jQuery插件快速增强用户体验,实现滑动效果、Ajax请求等; 深入Bootstrap框架,掌握移动优先的开发策略,响应式设计信手拈来。 无论是前端开发新手渴望系统学习,还是资深开发者寻求灵感与实用技巧,这份资源都是不可多得的宝藏。立即深入了解,开启你的全栈前端探索之旅,让每一个网页都成为技术与艺术的完美融合!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值