您的位置:首页 > 其它

bzoj2286 [Sdoi2011]消耗战 单调栈+lca

2018-01-17 19:50 411 查看
这个题意思非常明确,就是删除尽量小的边使1和指定点不连通
对于一次询问,dfs一遍即可,但需要log级别的
然后条件里有个Σ,显然复杂度和他有关,对每个点都需要一个均摊log的
然后有两个基本思路,
1、树分治
2、lca
1会打乱原树,所以不行,只有2
然后手玩发现一些东西:
1、一个点被选,子树就无所谓了
2、在一个子树内,lca是单调往上的
根据2,想办法利用这个单调性来解决问题
想到取dfs序,然后子树里lca就相当于是从下往上更新,会发现lca只有和询问点相同个
然后就用单调栈维护深度单调递减就可以了,和其他单调栈不同的就是更新有方向性
最后发现这其实是虚树的思想,只是这个题似乎不用建虚树,只需要单调栈逻辑判断一下就可以了。
码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define inf 10000000000009
#define ll long long
#define N 500005
int tot,sta
,f
,n,x,y,z,m,s,i,j,hou
,xia
,zhong
,v
,cnt,dfn
,sz
,d
,top
,zz,hson
,fu
;
ll g
,min1
;
void jian(int a,int b,int c)
{
++tot,hou[tot]=xia[a],zhong[tot]=b,xia[a]=tot,v[tot]=c;
}
void jia(int a,int b,int c)
{
jian(a,b,c);
jian(b,a,c);
}
void dfs1(int o,int fa,int dis,int minn)
{ int i,nd;
dfn[o]=++cnt;
sz[o]=1;d[o]=dis;fu[o]=fa;min1[o]=minn;
for(i=xia[o];i!=-1;i=hou[i])
{nd=zhong[i];
if(nd==fa)continue;
dfs1(nd,o,dis+1,min(minn,v[i]));
sz[o]+=sz[nd];if(sz[nd]>sz[hson[o]])hson[o]=nd;
}
}
void dfs2(int o,int tap)
{int i,nd;
top[o]=tap;
if(hson[o])dfs2(hson[o],tap);
for(i=xia[o];i!=-1;i=hou[i])
{nd=zhong[i];
if(nd==fu[o]||nd==hson[o])continue;
dfs2(nd,nd);
}
}
int getlca(int x,int y)
{
while(top[x]!=top[y])
{
if(d[top[x]]<d[top[y]])swap(x,y);
x=fu[top[x]];
}
if(d[x]>d[y])swap(x,y);
return x;
}
ll work()
{
int i;
zz=0;
sta[0]=1;
f[++s]=1;
sta[++zz]=f[1];
for(i=2;i<=s;i++)
{
int lin=getlca(f[i-1],f[i]);
while(d[lin]<d[sta[zz]]&&zz)
{
g[sta[zz]]=min(min1[sta[zz]],g[sta[zz]]);
if(d[sta[zz-1]]>d[lin])g[sta[zz-1]]+=g[sta[zz]]; //找小的贡献
else g[lin]+=g[sta[zz]];
g[sta[zz]]=0;
zz--;
}
if(lin!=sta[zz])sta[++zz]=lin;
if(f[i]!=sta[zz])sta[++zz]=f[i];
}
return g[1];
}
bool cmp(int a,int b)
{
return dfn[a]<dfn[b];
}
int main()
{memset(xia,-1,sizeof(xia));
scanf("%d",&n);
for(i=1;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
jia(x,y,z);
}
scanf("%d",&m);
dfs1(1,1,1,999999);
dfs2(1,1);
for(j=1;j<=m;j++)
{
scanf("%d",&s);
for(i=1;i<=s;i++)
{
scanf("%d",&f[i]);
g[f[i]]=min1[f[i]];
}
sort(f+1,f+1+s,cmp);
printf("%lld\n",work());
g[1]=0;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: