调了一万年......先是==写成=,然后快读出锅,手写队列以为出锅改成stl结果发现stl才是真正出锅....改回手写队列才a
抄题解都抄了好久好久...(写法不唯一...
然后BZOJ RE.........WDNMD
思路,找环,子树求直径,单调队列dp,比较好理解,但是写起来有点麻烦
这里用dfs找环,传bool型返回值,dfs时因为有重边不能直接记录fa,要按边记录,过程中把环上的点塞到数组里,记录每个点的下标和边权前缀和,并注意记录环的头尾衔接点
子树求直径用全局标记数组v2,环上的点在找环的时候已经在v2标记过了不用考虑,然后正常树形dp
单调队列dp,因为数组不清空,所以每次记录一下当前子树对应的下标起始点为st,dp的时候减一下偏移量
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #define ll long long using namespace std; const int maxn=1000009; inline int read(){ int ret=0,fix=1;char ch; while(!isdigit(ch=getchar()))fix=ch=='-'?-1:fix; do ret=(ret<<1)+(ret<<3)+ch-'0'; while(isdigit(ch=getchar())); return fix*ret; } int n,st;//st为本子树中环开始编号 struct node{ int v,nxt,w; }e[maxn<<1]; int head[maxn],cnt=1; inline void add(int u,int v,int w){ e[++cnt].v=v;e[cnt].nxt=head[u];head[u]=cnt;e[cnt].w=w; e[++cnt].v=u;e[cnt].nxt=head[v];head[v]=cnt;e[cnt].w=w; } //找环 int v[maxn],v2[maxn],id[maxn],tot; ll s[maxn<<1]; //v=1走过,v=2环的头尾衔接点 //v2=1所在基环树走过, //id原始编号 //s为边长度前缀和,dp用 bool dfs(int x,int last){ if(v[x]==1){ v[x]=2;id[++tot]=x,v2[x]=1; return 1; } v[x]=1; for(int i=head[x];i;i=e[i].nxt){ if(i!=(last^1)&&dfs(e[i].v,i)){ if(v[x]!=2)id[++tot]=x,v2[x]=1,s[tot]=s[tot-1]+e[i].w; else{ s[st-1]=s[st]-e[i].w; return 0; } return 1; } } return 0; } //子树直径 ll d[maxn],ans,ans2; void subdp(int x){ v2[x]=1; for(int i=head[x];i;i=e[i].nxt){ int y=e[i].v; if(v2[y])continue; subdp(y); ans=max(ans,d[x]+d[y]+e[i].w); d[x]=max(d[x],d[y]+e[i].w); } } //带环直径 ll f[maxn<<1],ans3; int q[maxn<<1],hd=1,tl; void dp(){ hd=1,tl=0; for(int i=st;i<=tot;i++){//环复制成链 f[i+tot-st+1]=f[i]=d[id[i]]; s[i+tot-st+1]=s[i+tot-st]+s[i]-s[i-1]; } for(int i=st;i<=tot*2-st+1;i++){ while(hd<=tl && q[hd]<=i-tot+st-1)hd++; if(hd<=tl)ans3=max(ans3,f[i]+f[q[hd]]+s[i]-s[q[hd]]); while(hd<=tl && f[q[tl]]-s[q[tl]]<=f[i]-s[i])tl--; q[++tl]=i; } // deque<int>q; // for(int i=st;i<=tot*2-st+1;i++){ // while(!q.empty() && q.front()<=i-tot+st-1)q.pop_front(); // if(!q.empty())ans3=max(ans3,f[i]+f[q.front()]+s[i]-s[q.front()]); // while(!q.empty() && f[q.front()]-s[q.front()]<=f[i]-s[i])q.pop_back(); // q.push_back(i); // } } ll work(int x){ st=tot+1,ans2=0,ans3=0; //找环 dfs(x,0); //子树直径 for(int i=st;i<=tot;i++){ ans=0; subdp(id[i]); ans2=max(ans2,ans); // f[i+tot-st+1]=f[i]=d[id[i]]; // s[i+tot-st+1]=s[i+tot-st]+s[i]-s[i-1]; } dp(); return max(ans2,ans3); } int main(){ scanf("%d",&n); // for(int i=1;i<=n;i++)add(i,read(),read()); for(int i=1,u,v;i<=n;i++){ scanf("%d%d",&u,&v); add(i,u,v); } ll anss=0; for(int i=1;i<=n;i++) if(!v2[i])anss+=work(i); printf("%lld",anss); // for(int i=1;i<=n;i++)printf("%d ",d[i]); }