题目链接

本代码10分(感觉速度还行。。)。

建圆方树,预处理一些东西。对询问建虚树。

对于虚树上的圆点直接做;对于方点特判,枚举其所有儿子,如果子节点不在该方点代表的环中,跳到那个点并更新其val,加入B数组;对于环中的点直接加入B数组。

然后像BZOJ2125一样更新环上的。懒得写拆环的单调队列了,直接用min(abs,len-abs)。

UOJ特么的数据有毒啊。调不出来了,AC的代码一个比一个码风奇特,还有的贼长。。先不调了。

一上午+半下午了。。从注释的代码可以看出调的过程多么鬼畜。

//5.81KB→_→
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=(3e5+5)*2,INF=1e9; int n,m,Q,K,A[N],B[N],tot,D[N],fat[N][20],dfn[N],low[N],Index,tp[N],dep[N],fa[N],son[N],sz[N],sk[N],top,q[N];
LL dis[N],cdis[N],length[N],f[N],Ans,val[N],len[N][20];
bool tag[N],vis[N];
struct Graph
{
int Enum,H[N],nxt[N<<1],to[N<<1];//边数:仙人掌:2*2n 圆方树:1*2n 虚树:1*2K
LL len[N<<1];
inline void Init(){
Enum=0, memset(H,0,sizeof H);
}
inline void Add_direct(int u,int v,LL w)
{
// printf("Add_direct:%d->%d:",u,v);
to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
if(~w) len[Enum]=w;//,printf("%I64d\n",w);
else len[Enum]=dis[v]-dis[u];//,printf("%I64d\n",len[Enum]);
}
inline void AddEdge(int u,int v,int w)
{
to[++Enum]=v, nxt[Enum]=H[u], len[Enum]=w, H[u]=Enum;
to[++Enum]=u, nxt[Enum]=H[v], len[Enum]=w, H[v]=Enum;
}
}T,G; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline bool cmp_dfn(const int &a,const int &b){
return dfn[a]<dfn[b];
}
void Build(int u,int v,int w)
{
// printf("Build:%d->...->%d\n",v,u);
LL len=w;
for(int x=v; x!=u; x=fa[x]) cdis[x]=len, len+=D[x];
length[++tot]=len, T.Add_direct(u,tot,0);
for(int x=v; x!=u; x=fa[x]) T.Add_direct(tot,x,std::min(cdis[x],len-cdis[x]));
}
void Tarjan(int x)
{
dfn[x]=low[x]=++Index;
for(int v,i=G.H[x]; i; i=G.nxt[i])
if(!dfn[v=G.to[i]]) D[v]=std::min((LL)D[v],G.len[i]);
for(int v,i=G.H[x]; i; i=G.nxt[i])
if((v=G.to[i])!=fa[x])
{
if(!dfn[v]) fa[v]=x, Tarjan(v), low[x]=std::min(low[x],low[v]);
else low[x]=std::min(low[x],dfn[v]);
if(low[v]>dfn[x]&&!vis[v]) T.Add_direct(x,v,D[v]), vis[v]=1;
}
for(int v,i=G.H[x]; i; i=G.nxt[i])
if(fa[v=G.to[i]]!=x&&dfn[v]>dfn[x]) Build(x,v,G.len[i]);
}
void DFS1(int x)
{
int mx=0; sz[x]=1;
for(int v,i=T.H[x]; i; i=T.nxt[i])
if((v=T.to[i])!=fa[x])//
{
v=T.to[i];
fa[v]=fat[v][0]=x, len[v][0]=T.len[i], dep[v]=dep[x]+1, dis[v]=dis[x]+T.len[i], DFS1(v), sz[x]+=sz[v];
if(mx<sz[v]) mx=sz[v], son[x]=v;
}
}
void DFS2(int x,int _tp)
{
dfn[x]=++Index, tp[x]=_tp;
if(son[x]){
DFS2(son[x],_tp);
for(int i=T.H[x]; i; i=T.nxt[i])
// if(T.to[i]!=son[x]) DFS2(T.to[i],T.to[i]);
if(T.to[i]!=fa[x]&&T.to[i]!=son[x]) DFS2(T.to[i],T.to[i]);
}
}
void Init_ST()
{
for(int x=1; x<=tot; ++x)
for(int j=1; j<20; ++j)
fat[x][j]=fat[fat[x][j-1]][j-1], len[x][j]=len[x][j-1]+len[fat[x][j-1]][j-1];
}
int LCA(int u,int v)//既然要用倍增了也许可以改成倍增
{
while(tp[u]!=tp[v]) dep[tp[u]]>dep[tp[v]]?u=fa[tp[u]]:v=fa[tp[v]];
return dep[u]>dep[v]?v:u;
}
void Insert(int p)
{
if(top==1) {sk[++top]=p; return;}
int lca=LCA(sk[top],p);
while(dfn[sk[top-1]]>=dfn[lca]) G.Add_direct(sk[top],sk[top--],-1);
if(lca!=sk[top] && dfn[sk[top-1]]<dfn[lca]) G.Add_direct(lca,sk[top],-1), sk[top]=lca;
sk[++top]=p;
}
inline LL Cir_dis(int u,int v,int cir){
return std::min(std::abs(cdis[u]-cdis[v]),length[cir]-std::abs(cdis[u]-cdis[v]));
}
inline LL Dis(int u,int v,int cir){
return val[u]+Cir_dis(u,v,cir);
}
int Jump(int x,LL d)
{
LL res=0;
// printf("Jump:%d %I64d:",x,d);
for(int i=19; ~i; --i)
if(dis[fat[x][i]]>=d) res+=len[x][i], x=fat[x][i];
// printf("%d %I64d\n",x,res);
return val[x]=std::max(val[x],res), x;
}
void Solve(int x)//Square Point
{
// printf("\nSolve:%d\n",x);
int cnt=0;
// if(tag[fa[x]]) B[cnt=1]=fa[x];//
for(int v,i=G.H[x]; i; i=G.nxt[i])
if(fa[v=G.to[i]]==x||fa[x]==v) val[B[++cnt]=v]=f[v];
else B[++cnt]=Jump(v,dis[x]+1);
int h=1,t=0;
for(int v,i=1; i<=cnt; ++i)
{
if(h>t) {q[++t]=B[i]; continue;}
v=B[i];
while(h<t && Dis(q[h],v,x)<Dis(q[h+1],v,x)) ++h;
// printf("q[h]:%d v:%d Dis:%I64d\n",q[h],v,Dis(q[h],v,x));
Ans=std::max(Ans,Dis(q[h],v,x)+val[v]);
while(h<t && Dis(q[t],v,x)<val[v]) --t;
q[++t]=v;
}
for(int v,i=1; i<=cnt; ++i)
f[x]=std::max(f[x],val[B[i]]+Cir_dis(fa[x],B[i],x));
for(int i=1; i<=cnt; ++i) val[B[i]]=0;
// putchar('\n');
}
void DP(int x)//G:Virtual Tree
{
f[x]=tag[x]?0:-INF;
// printf("Now:%d\n",x);
if(x<=n){//Round Point
for(int v,i=G.H[x]; i; i=G.nxt[i])
DP(v=G.to[i]), Ans=std::max(Ans,f[x]+f[v]+G.len[i]), f[x]=std::max(f[x],f[v]+G.len[i]);
// printf("%d->%d:end Ans:%I64d f[x]:%I64d\n",x,v,Ans,f[x]);
}
else{
for(int i=G.H[x]; i; i=G.nxt[i]) DP(G.to[i]);
Solve(x);
}
// printf("%d:tag:%d f:%I64d Ans:%I64d\n",x,tag[x],f[x],Ans);
G.H[x]=tag[x]=0;
} int main()
{
// freopen("1.in","r",stdin);
tot=n=read(),m=read();
for(int u,v,i=1; i<=m; ++i) u=read(),v=read(),G.AddEdge(u,v,read());
// memset(D,0x7f,sizeof D);//0x7fffffff
for(int i=1; i<=n; ++i) D[i]=0x7fffffff;
Tarjan(1), fa[1]=Index=0, DFS1(1), DFS2(1,1), Init_ST(), G.Init();
Q=read();//puts("\ndis:");
// for(int i=1; i<=tot; ++i) printf("%d:%I64d\n",i,dis[i]);putchar('\n');
while(Q--)
{
K=read(); for(int i=1; i<=K; ++i) tag[A[i]=read()]=1;
std::sort(A+1,A+1+K);
int k=K; K=1;//unique //有重这有毒啊
for(int i=2; i<=k; ++i) if(A[i]!=A[i-1]) A[++K]=A[i]; std::sort(A+1,A+1+K,cmp_dfn);
sk[top=1]=1;
if(A[1]==1) for(int i=2; i<=K; ++i) Insert(A[i]);
else for(int i=1; i<=K; ++i) Insert(A[i]);
while(--top) G.Add_direct(sk[top],sk[top+1],-1); Ans=0, DP(1), G.Enum=0;
printf("%lld\n",Ans);
}
return 0;
}

UOJ.87.mx的仙人掌(圆方树 虚树)(未AC)的更多相关文章

  1. uoj#87. mx的仙人掌

    //Achen #include<bits/stdc++.h> #define For(i,a,b) for(int i=(a);i<=(b);i++) #define Rep(i, ...

  2. 仙人掌&圆方树学习笔记

    仙人掌&圆方树学习笔记 1.仙人掌 圆方树用来干啥? --处理仙人掌的问题. 仙人掌是啥? (图片来自于\(BZOJ1023\)) --也就是任意一条边只会出现在一个环里面. 当然,如果你的图 ...

  3. 仙人掌 && 圆方树 && 虚树 总结

    仙人掌 && 圆方树 && 虚树 总结 Part1 仙人掌 定义 仙人掌是满足以下两个限制的图: 图完全联通. 不存在一条边处在两个环中. 其中第二个限制让仙人掌的题做 ...

  4. 仙人掌&圆方树

    仙人掌&圆方树 Tags:图论 [x] [luogu4320]道路相遇 https://www.luogu.org/problemnew/show/P4320 [ ] [SDOI2018]战略 ...

  5. [SDOI2018]战略游戏(圆方树+虚树)

    喜闻乐见的圆方树+虚树 图上不好做,先建出圆方树. 然后答案就是没被选到的且至少有两条边可以走到被选中的点的圆点的数量. 语文不好,但结论画画图即可得出. 然后套路建出虚树. 发现在虚树上DP可以得出 ...

  6. BZOJ.2125.最短路(仙人掌 圆方树)

    题目链接 圆方树.做题思路不写了.. 就是当LCA是方点时跳进那个环可以分类讨论一下用树剖而不必须用倍增: 如果v是u的(唯一的那个)重儿子,那么u的DFS序上+1的点即是要找的:否则v会引出一条新的 ...

  7. BZOJ5329:[SDOI2018]战略游戏(圆方树,虚树)

    Description 省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏. 这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着 ...

  8. BZOJ.5329.[SDOI2018]战略游戏(圆方树 虚树)

    题目链接 显然先建圆方树,方点权值为0圆点权值为1,两点间的答案就是路径权值和减去起点终点. 对于询问,显然可以建虚树.但是只需要计算两关键点间路径权值,所以不需要建出虚树.统计DFS序相邻的两关键点 ...

  9. Codechef Sad Pairs——圆方树+虚树+树上差分

    SADPAIRS 删点不连通,点双,圆方树 非割点:没有影响 割点:子树DP一下 有不同颜色,所以建立虚树 在圆方树上dfs时候 如果当前点是割点 1.统计当前颜色虚树上的不连通点对,树形DP即可 2 ...

随机推荐

  1. 【方法】jQuery无插件实现 鼠标拖动切换图片/内容 功能

    前言 我就想随便叨逼叨几句,爱看就看几句,不爱看就直接跳过看正文就好啦~ 这个方法是仿写页面时我自己研究出来,可能有比我更简单的方法. 但我不管,因为我没查我不知道,我就觉得我的最好啦,耶耶耶~ 效果 ...

  2. 状压dp(B - 炮兵阵地 POJ - 1185 )

    题目链接:https://cn.vjudge.net/contest/276236#problem/B 题目大意:略  具体思路:和我的上一篇写状压dp的思路差不多,不过就是这个题相当于上一个题的升级 ...

  3. Servlet笔记2--模拟Servlet本质、第一个Servlet程序、将响应结果输出到浏览器中

    以下代码均非IDE开发,所以都不规范,仅供参考 模拟Servlet本质: 模拟Servlet接口: /* SUN公司制定的JavaEE规范:Servlet规范 Servlet接口是Servlet规范中 ...

  4. Hibernate5笔记2--单表的增删改查操作

    单表的增删改查操作: (1)定义获取Session和SessionFactory的工具类: package com.tongji.utils; import org.hibernate.Session ...

  5. springcloud中eureka集群unavailable-replicas

    unavailable-replicas 配置了集群,但是在注册中心显示另外的几个集群地址是不可用的: 1 首先需要再host中添加服务名映射,如果应映射了再看是否在yml中配置了prefer-ip- ...

  6. XSS练习小游戏和答案参考

    源码:https://files.cnblogs.com/files/Eleven-Liu/xss%E7%BB%83%E4%B9%A0%E5%B0%8F%E6%B8%B8%E6%88%8F.zip 感 ...

  7. Django BoundField

    一.BoundField from django.forms.boundfield import BoundField BoundField是一个将字段添加数据的一个类,给对应的form字段封装上数据 ...

  8. 九、springcloud之服务网关zuul(二)

    一.路由熔断 当我们的后端服务出现异常的时候,我们不希望将异常抛出给最外层,期望服务可以自动进行一降级.Zuul给我们提供了这样的支持.当某个服务出现异常时,直接返回我们预设的信息. 我们通过自定义的 ...

  9. 不同意义的new和delete

    补充说明: new/delete是运算符而非函数,operator new/delete并非是new/delete的重载.事实上,我们无法自定义new/delete的行为: operator new/ ...

  10. Tango ROS Streamer

    谁想要在Android平台上编写机器人应用,或者谁希望扩展其与室内定位和3D感知新的传感器的机器人开发,Intermodalics创建的ROS Streamer应用的Tango. 这个Android应 ...