马上区域赛了 ,每天刷一些自己以前写过的题,记录在博客里督促自己,
点分治:poj1741,求树上长度在kr区间内的路径个数
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=1e4+4,inf = 0x3f3f3f3f;
#define ll long long
struct Node{int to,nex,w;}e[M<<1];
int n,k,head[M<<1],cnt,mx,vis[M],rt,sum,siz[M];
ll rhs=0,d[M<<1];
void getrt(int x,int f,int mm=0){
siz[x]=1;
for(int to,i=head[x];~i;i=e[i].nex){
to=e[i].to;
if(vis[to]||to==f)continue;
getrt(to,x);
siz[x]+=siz[to];
if(mm<siz[to])mm=siz[to];
}
if(mm<sum-siz[x])mm=sum-siz[x];
if(mx>mm)mx=mm,rt=x;
}
void dfs(int x,int f){
siz[x]=1;
for(int to,i=head[x];~i;i=e[i].nex){
to=e[i].to;
if(vis[to]||to==f)continue;
dfs(to,x);
siz[x]+=siz[to];
}
}
void getdis(int x,int f,ll dis){
// cout<<x<<endl;
d[++d[0]]=dis;
for(int to,i=head[x];~i;i=e[i].nex){
to=e[i].to;
if(vis[to]||to==f)continue;
getdis(to,x,dis+e[i].w);
}
}
ll calc(int x,int f,ll dis){
ll ans=0;d[0]=0;
getdis(x,f,dis);
// cout<<d[0]<<endl;
sort(d+1,d+d[0]+1);
int l=1,r=d[0];
while(l<r){
if(d[l]+d[r]<=k)ans+=r-l,l++;
else r--;
}
return ans;
}
void slove(int x){
rhs += calc(x,0,0);
vis[x]=1;
// cout<<x<<":"<<rhs<<endl;
for(int to,i=head[x];~i;i=e[i].nex){
to=e[i].to;
if(vis[to])continue;
rhs-=calc(to,x,e[i].w);//容斥原理
mx=inf;
sum=siz[to];
getrt(to,0);
dfs(rt,0);
slove(rt);
}
}
int main(){
while(~scanf("%d%d",&n,&k)){
if(n==0&&k==0)return 0;
memset(head,-1,sizeof(head)); cnt=1;
memset(vis,0,sizeof(vis)); rhs=0;
for(int x,y,w,i=1;i<n;i++){
scanf("%d%d%d",&x,&y,&w);
e[cnt].to=y; e[cnt].w=w; e[cnt].nex=head[x]; head[x]=cnt++;
e[cnt].to=x; e[cnt].w=w; e[cnt].nex=head[y]; head[y]=cnt++;
}
mx=inf;
sum=n;
getrt(1,0);
dfs(rt,0);
slove(rt);
printf("%lld\n",rhs);
}
return 0;
}
10.15 21:32 长链剖分:洛谷3899
题目描述
设 T 为一棵有根树,我们做如下的定义:
• 设 a 和 b 为 T 中的两个不同节点。如果 a 是 b 的祖先,那么称“a 比 b 不知道高明到哪里去了”。
• 设 a 和 b 为 T 中的两个不同节点。如果 a 与 b 在树上的距离不超过某个给定常数 x,那么称“a 与 b 谈笑风生”。
给定一棵 n 个节点的有根树 T,节点的编号为 1 ∼ n,根节点为 1 号节点。你需要回答 q 个询问,询问给定两个整数 p 和 k,问有多少个有序三元组 (a; b; c) 满足:
-
a、 b 和 c 为 T 中三个不同的点,且 a 为 p 号节点;
-
a 和 b 都比 c 不知道高明到哪里去了;
-
a 和 b 谈笑风生。这里谈笑风生中的常数为给定的
#include<bits/stdc++.h> using namespace std; using ll = long long ; constexpr int M=3e5+5; struct Node{int to,nex;}e[M<<1]; struct node{int k,id;}; int n,m,cnt,dis[M],siz[M],len[M],son[M],head[M<<1]; ll ans[M],tmp[M],*id=tmp,*f[M]; vector<node> q[M]; void dfs1(int x,int f){ siz[x]=1; for(int to,i=head[x];~i;i=e[i].nex){ to=e[i].to; if(to==f)continue; dis[to]=dis[x]+1; dfs1(to,x); siz[x]+=siz[to]; if(len[son[x]]<len[to])son[x]=to; } len[x]=len[son[x]]+1; } void dfs2(int x,int fa){ if(son[x]) f[son[x]]=f[x]+1,dfs2(son[x],x); for(int to,i=head[x];~i;i=e[i].nex){ to=e[i].to; if(to==fa||to==son[x])continue; f[to]=id;id+=len[to]; dfs2(to,x); for(int j=0;j<len[to];j++)f[x][j+1]+=f[to][j]; } for(int k,id,i=0;i<q[x].size();i++){ k=q[x][i].k; id=q[x][i].id; ans[id]=(ll)(siz[x]-1)*min(k,dis[x]); if(len[x]<=k+1)ans[id]+=f[x][1]; else ans[id]+=f[x][1]-f[x][k+1]; } f[x][0]=f[x][1]+siz[x]-1; } int main(){ memset(head,-1,sizeof(head));cnt=1; scanf("%d%d",&n,&m); for(int x,y,i=1;i<n;i++){ scanf("%d%d",&x,&y); e[cnt].to=y; e[cnt].nex=head[x]; head[x]=cnt++; e[cnt].to=x; e[cnt].nex=head[y]; head[y]=cnt++; } for(int x,k,i=1;i<=m;i++){ scanf("%d%d",&x,&k); q[x].push_back((node){k,i}); } dfs1(1,0); f[1]=id;id+=len[1]; dfs2(1,0); for(int i=1;i<=m;i++)printf("%lld\n",ans[i]); return 0; }
树上主席树+树剖lca:洛谷2633
#include<bits/stdc++.h> using namespace std; const int M=1e5+5; #define ll long long struct Edge{ll to,nex;}e[M<<1]; struct Node{ll ls,rs,sum;}t[M*40]; ll las,n,m,d[M],b[M],head[M<<1],cnt,rot[M]; ll siz[M],son[M],fa[M],top[M],dep[M]; void dfs1(ll x,ll f){ siz[x]=1; fa[x]=f; for(ll to,i=head[x];~i;i=e[i].nex){ to=e[i].to; if(to==f)continue; dfs1(to,x); siz[x]+=siz[to]; if(siz[son[x]]<siz[to])son[x]=to; } } void dfs2(ll x,ll tp){ top[x]=tp; if(son[x])dfs2(son[x],tp); for(ll to,i=head[x];~i;i=e[i].nex){ to=e[i].to; if(to!=son[x]&&to!=fa[x])dfs2(to,to); } } ll lca(ll x,ll y){ while(top[x]!=top[y]) if(dep[top[x]]<dep[top[y]]) y=fa[top[y]]; else x=fa[top[x]]; return dep[x]<dep[y]?x:y; } void build(ll &k,ll l,ll r){ k=++cnt; t[k].sum=t[k].ls=t[k].rs=0; if(l==r)return ; ll mid=(l+r)>>1; build(t[k].ls,l,mid); build(t[k].rs,mid+1,r); } void update(ll &k,ll pre,ll l,ll r,ll v){ k=++cnt; t[k]=t[pre]; t[k].sum++; if(l==r)return ; ll mid=(l+r)>>1; if(v<=mid) update(t[k].ls, t[pre].ls, l,mid, v); else update(t[k].rs, t[pre].rs, mid+1,r, v); } void dfs(ll x,ll f){ dep[x]=dep[f]+1; update(rot[x],rot[f],1,b[0],d[x]); for(ll i=head[x];~i;i=e[i].nex) if(e[i].to!=f) dfs(e[i].to,x); } ll ask(ll k,ll pre,ll l,ll r,ll now,ll lcaa,ll flca){ if(l==r)return l; ll mid=(l+r)>>1,num=t[ t[k].ls ].sum+t[ t[pre].ls ].sum - t[ t[lcaa].ls ].sum -t[ t[flca].ls ].sum; if(now<=num)return ask(t[k].ls,t[pre].ls,l,mid,now,t[lcaa].ls,t[flca].ls); return ask(t[k].rs,t[pre].rs,mid+1,r,now-num,t[lcaa].rs,t[flca].rs); } int main(){ memset(head,-1,sizeof(head)); cnt=1; scanf("%lld%lld",&n,&m); for(ll i=1;i<=n;i++)scanf("%lld",&d[i]),b[i]=d[i]; sort(b+1,b+n+1);//手写unique离散化 b[0]=1;for(ll i=2;i<=n;i++) if(b[i]!=b[i-1])b[++b[0]]=b[i]; for(ll i=1;i<=n;i++) d[i]=lower_bound(b+1,b+b[0]+1,d[i])-b; for(ll x,y,i=1;i<n;i++){ scanf("%lld%lld",&x,&y); e[cnt].to=y; e[cnt].nex=head[x]; head[x]=cnt++;//链式前向星建图 e[cnt].to=x; e[cnt].nex=head[y]; head[y]=cnt++; } cnt=0;//树链剖分lca dfs1(1,0); dfs2(1,1); cnt=0; build(rot[0],1,b[0]);//树上主席树初始化 dfs(1,0); for(ll u,v,k,i=1;i<=m;i++){ scanf("%lld%lld%lld",&u,&v,&k); u^=las; if(dep[u]<dep[v])swap(u,v); las=ask(rot[u],rot[v],1,b[0],k,rot[lca(u,v)],rot[fa[lca(u,v)]]); las=b[las]; printf("%lld\n",las); } return 0; }