题解:
因为w大于1,所以,题意就是,有多少(x,z),存在x到z的路径上,有一个x<y<z的y
w没用的其实。
树上路径问题,有什么方法吗?
1.树链剖分。这个主要方便处理修改操作。
2.点分治,对于静态无修改点树上统计,非常好用。
3.一些其他的:
利用lca,dfs序,判断点在路径上,点在子树里一些情况。
倍增,处理fa[N][20],dis[N][20] ,
二分再套一个倍增?
4.还有一些灵活应变的:
例如:拆路径为x到lca,lca到y,可以在x,y记录一些lca的信息,把路径就变成了点。
这个题,静态无修树上统计,就点分治了。
还可以再带一个log
那么当前层的重心G,统计过G路径。
树形背包思想,直接统计z能和之前的那些x凑成点对,记录x到G路径上的大于x最小的编号nx(因为是存在,不是任意嘛)
然后记录z到G路径上小于z的最大编号pz
如果pz>x,那么可以
如果nx<y,那么可以
但是pz<nx的情况被算重了。去重要用二维数据结构两个log就TLE了。
正难则反。考虑所有的点对。C(n,2)
对于x到z路径上都比x,z小的去掉,都比x、z大的去掉。就可以了。
具体来说,维护一个树状数组,
以去掉路径上都比x、z小的为例:
之前访问的作为x,如果x到根节点的路径上(包括根)最大值(不存在就是一个任意问题了)小于x,把x位置++
dfs统计,对于z,如果G到z路径上的最大值mx小于z,统计query(z-1)-query(mx)
表示得到编号在mx+1到z-1的x,且x到根路径上的最大值小于x的x数量。
就可以去掉这部分。
当然,因为G儿子的循环顺序,必须正序循环一遍,再倒序循环一遍。当前都作为z,之前的作为x,一定不会漏
另一个都比x,z大的同理。
而且之后统计路径上比x、z都大的情况不会算重。
小细节:
1.C(n,2)会爆int
2.子树的sz不是开始统计的sz,递归之前,必须从新的根即重心G再dfs统计sz
3.点分治一定要时刻控制:if(vis[e[i].to]) continue 否则T得飞起,WA的痛快。
4.发现,对于每条边的两端点对,会被减掉两次。
所以,ans开始还要加上(n-1)
代码:
#include
using namespace std;
typedef long long ll;
const int N=+;
const int inf=0x3f3f3f3f;
ll n;
int rt,nowsz;
bool vis[N];
int mxsz[N],sz[N];
int f[N];
void add(int x,int c){//树状数组
for(;x<=n;x+=x&(-x)) f[x]+=c;
}
int query(int x){
int ret=;for(;x;x-=x&(-x)) ret+=f[x];return ret;
}
int sta[N],top;
int mxid[N],miid[N];//路径上编号最小值,最大值
ll ans;
struct node{
int nxt,to;
int pre;
}e[*N];
int hd[N],cnt;
int las[N];
void con(int x,int y){//注意建立双向邻接表,便于反过来dfs
if(hd[x]&&e[hd[x]].nxt==) las[x]=hd[x];
e[++cnt].nxt=hd[x];
e[hd[x]].pre=cnt;
e[cnt].to=y;
hd[x]=cnt;
}
void dfs0(int x,int fa){//dfs0找根
sta[++top]=x;
mxid[x]=;mxsz[x]=;
miid[x]=;
sz[x]=;
for(int i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa) continue;
if(vis[y]) continue;
dfs0(y,x);
sz[x]+=sz[y];
mxsz[x]=max(mxsz[x],sz[y]);
}
if(mxsz[x]<=nowsz/&&(nowsz-sz[x])<=nowsz/) rt=x;
}
void fsz(int x,int fa){//找完rt更新sz
sz[x]=;
for(int i=hd[x];i;i=e[i].nxt){
if(vis[e[i].to]) continue;
if(e[i].to!=fa){
fsz(e[i].to,x);
sz[x]+=sz[e[i].to];
}
}
}
void dfs1(int x,int mx,int fa){//dfs1统计答案,对于路径上的点都比x,z小的。
mxid[x]=mx;
if(mx
if(mx
memset(vis,,sizeof vis);//解开封锁
top=;
nowsz=n;
dvi2();
printf("%lld",ans);
return ;
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章