题目链接:http://codeforces.com/contest/827/problem/D
数据结构,很休闲的。。。
首先我们要生成一颗最小生成树,然后,对于树上的边,答案是树外边中的最小值-1,其中树外边指的是在最小生成树过程中,可以替代当前边的所有边,然后对于每一个不在最小生成树上的边(u,v),答案是树上从u到v路径的最大值-1
然后我们对这两种情况分开维护,对于树上路径,我们用LCA可以在logn时间内求出某个路径的最大值,对于树外的每条边(u,v),他对所有在u到v路径上的边都有贡献,这就需要支持修改树上路径的操作,我们用树链剖分维护,单词操作复杂度也是logn,总体在O(nlogn)内就可以解决
貌似不用这么麻烦???
代码:
#include
using namespace std;
const int INF=0x3f3f3f3f;
bool book[200010];
struct E
{
int u,v,w;
}sv[200010];
namespace LCA
{
const int MAXN=200010;
const int DEG=20;
struct Edge
{
int to,next,w;
}edge[MAXN*2];
int head[MAXN],tot;
void addedge(int u,int v,int w)
{
edge[tot].to=v;
edge[tot].w=w;
edge[tot].next=head[u];
head[u]=tot++;
}
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
int fa[MAXN][DEG],mx[MAXN][DEG];//fa[i][j]表示结点i的第2^j个祖先
int deg[MAXN];//深度数组
void BFS(int root)
{
queueque;
deg[root]=0;
fa[root][0]=root;
mx[root][0]=0;
que.push(root);
while(!que.empty())
{
int tmp=que.front();
que.pop();
for(int i=1;ideg[v])swap(u,v);
int ret=0;
int hu=deg[u],hv=deg[v];
int tu=u,tv=v;
for(int det=hv-hu,i=0;det;det>>=1,i++)
if(det&1)
{
ret=max(mx[tv][i],ret);
tv=fa[tv][i];
}
if(tu==tv)
return ret;
for(int i=DEG-1;i>=0;i--)
{
if(fa[tu][i]==fa[tv][i])
continue;
ret=max(ret,mx[tu][i]);
ret=max(ret,mx[tv][i]);
tu=fa[tu][i];
tv=fa[tv][i];
}
return max(ret,max(mx[tu][0],mx[tv][0]));
}
}
namespace Kruskal
{
const int MAXN=2e5+5;//最大点数
const int MAXM=2e5+5;//最大边数
int F[MAXN];//并查集使用
struct Edge
{
int u,v,w,id;
}edge[MAXM];//存储边的信息,包括起点/终点/权值
int tol;//边数,加边前赋值为0
void init()//初始化
{
tol=0;
memset(F,-1,sizeof(F));
memset(edge,0,sizeof(edge));
}
void addedge(int u,int v,int w,int id)
{
edge[tol].u=u;
edge[tol].v=v;
edge[tol].id=id;
edge[tol++].w=w;
}
bool cmp(Edge a,Edge b)//排序函数,讲边按照权值从小到大排序
{
return a.wnum[son[u]])
son[u]=v;
}
}
}
void getpos(int u,int sp) //第二遍dfs求出top和p
{
top[u]=sp;
p[u]=pos++;
fp[p[u]]=u;
if(son[u]==-1)
return;
getpos(son[u],sp);
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(v!=son[u]&&v!=fa[u])
getpos(v,v);
}
}
//线段树
struct Node
{
int Min,lazy;
}segTree[MAXN*4];
void build(int i,int l,int r)
{
segTree[i].Min=INF;
segTree[i].lazy=0;
if(l==r)
return;
int mid=(l+r)>>1;
build(i<<1,l,mid);
build((i<<1)|1,mid+1,r);
}
void push_up(int i)
{
segTree[i].Min=max(segTree[i<<1].Min,segTree[(i<<1)|1].Min);
}
void push_down(int i)
{
if(segTree[i].lazy)
{
segTree[i<<1].Min=min(segTree[i<<1].Min,segTree[i].lazy);
segTree[i<<1|1].Min=min(segTree[i<<1|1].Min,segTree[i].lazy);
if(segTree[i<<1].lazy==0)
segTree[i<<1].lazy=segTree[i].lazy;
else
segTree[i<<1].lazy=min(segTree[i<<1].lazy,segTree[i].lazy);
if(segTree[i<<1|1].lazy==0)
segTree[i<<1|1].lazy=segTree[i].lazy;
else
segTree[i<<1|1].lazy=min(segTree[i<<1|1].lazy,segTree[i].lazy);
segTree[i].lazy=0;
}
}
void update(int L,int R,int val,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
segTree[rt].Min=min(segTree[rt].Min,val);
if(segTree[rt].lazy==0)
segTree[rt].lazy=val;
else
segTree[rt].lazy=min(segTree[rt].lazy,val);
return;
}
push_down(rt);
int mid=(l+r)>>1;
if(L<=mid)
update(L,R,val,lson);
if(mid>1;
push_down(rt);
if(pos<=mid)
return query(pos,lson);
if(middeep[v])
swap(u,v);
update(p[son[u]],p[v],val,0,pos-1,1);
}
int find(int u,int v)//查询u->v边的最大值
{
if(deep[u]>deep[v])
swap(u,v);
return query(p[v],0,pos-1,1);
}
}
void Kru(int n)//传入点数,返回最小生成树的权值,如果不连通返回-1
{
using namespace Kruskal;
memset(F,-1,sizeof(F));
sort(edge,edge+tol,cmp);
int cnt=0;//计算加入的边数
for(int i=0;i