• CF1413F Roads and Ramen 题解


    Codeforces
    Luogu

    Description.

    给定一个树,边带权 \(0,1\),支持单边翻转。
    每次查询长度为 \(0\) 的链的最大值。

    Solution.

    首先我们发现了一个性质,答案路径必然经过直径一端。
    详细证明参见这篇题解,感性理解的话就是从直径不断删一端的边。
    然后就做完了,可以考虑维护单点的深度,然后支持区间乘上 \(-1\),查询区间最大值。

    Coding.

    点击查看乐瑟代码
    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
    const int N=500005;struct edge{int to,w,nxt;}e[N<<1];int et=1,head[N],id[N],Ca,q[N];
    int n,d[N],ds[N],sz[N],dfn[N],dt,nfd[N],rs[N];struct segm{int mx,mn,fg;}T[N<<2];
    inline void adde(int x,int y,int w) {e[++et]=(edge){y,w,head[x]},head[x]=et;}
    inline void allc(int x) {swap(T[x].mx,T[x].mn),T[x].mx=-T[x].mx,T[x].mn=-T[x].mn,T[x].fg^=1;}
    inline void pushdw(int x) {if(T[x].fg) allc(x<<1),allc(x<<1|1),T[x].fg=0;}
    inline void pushup(int x) {T[x].mx=max(T[x<<1].mx,T[x<<1|1].mx),T[x].mn=min(T[x<<1].mn,T[x<<1|1].mn);}
    inline void build(int x,int l,int r)
    {
    	T[x].fg=0;if(l==r) return T[x].mx=T[x].mn=d[nfd[l]],void();
    	build(x<<1,l,(l+r)>>1),build(x<<1|1,((l+r)>>1)+1,r),pushup(x);
    }
    inline void modif(int x,int l,int r,int dl,int dr)
    {
    	if(l>dr||dl>r) return;else if(dl<=l&&r<=dr) return allc(x);else pushdw(x);
    	modif(x<<1,l,(l+r)>>1,dl,dr),modif(x<<1|1,((l+r)>>1)+1,r,dl,dr),pushup(x);
    }
    inline void dfs0(int x,int fa)
    {
    	d[x]=d[fa]+1;for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa) dfs0(e[i].to,x);
    }
    inline void dfs1(int x,int fa)
    {
    	sz[x]=1,dfn[x]=++dt,nfd[dt]=x;for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=fa)
    		ds[e[i].to]=ds[x]+e[i].w,dfs1(e[i].to,x),sz[x]+=sz[e[i].to],id[i>>1]=e[i].to;
    }
    inline void chg(int x) {x=id[x],modif(1,1,n,dfn[x],dfn[x]+sz[x]-1);}
    inline void solve()
    {
    	int rt=0;for(int i=1;i<=n;i++) if(d[rt]<=d[i]) rt=i;
    	dt=0,d[0]=-1,dfs0(rt,0),dfs1(rt,0),build(1,1,n);
    	for(int i=1;i<n;i++) if(e[i<<1].w==1) chg(i);
    	for(int i=1;i<=Ca;i++) chg(q[i]),rs[i]=max(rs[i],T[1].mx);
    }
    int main()
    {
    	read(n);for(int i=1,x,y,w;i<n;i++) read(x,y,w),adde(x,y,w),adde(y,x,w);
    	dfs0(1,0);read(Ca);for(int i=1;i<=Ca;i++) read(q[i]);
    	solve(),solve();for(int i=1;i<=Ca;i++) printf("%d\n",rs[i]);
    	return 0;
    }
    
  • 相关阅读:
    Java生成json
    WinForm程序执行JS代码的多种方法以及使用WebBrowser与JS交互
    聚集索引和非聚集索引的区别
    如何编写函数才能提高代码质量
    前端程序员应该知道的15个 jQuery 小技巧
    FileShare枚举的使用(文件读写锁)
    ASP.NET MVC 数据库依赖缓存的实现
    C# 调用一个按钮的Click事件(利用反射)
    解决报错“超时时间已到。超时时间已到,但是尚未从池中获取连接”的方案
    关于浏览器URL中出现会话验证字符说明
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15235868.html
Copyright © 2020-2023  润新知