很有趣,比赛时打了个暴搜就过了。
以后还有仙人掌分治(瞎猜)怎么办……
很容易想到,在环上拆掉一条边,然后求点对,在计算只通过这条边的点对,就好了!!!
正难则反。
只通过这条边的点对=删边前可以的点对-删边后和删边前都可以的点对。
所以,删边前可以的点对=ans=只通过这条边的点对+删边后和删边前都可以的点对
设删掉的边是(tou,wei),有数组aa[i]表示每个点到tou的距离,bb[i]表示每个点到wei的距离。
把aa[i]
可以用正常的点分治计算删掉一条边后,然后再顺便用上面的方法统计符合当前树分治条件,又符合通过删去的那条边的条件,当然也是用树状数组来统计。
我就被一个无关紧要的常数优化卡掉了60分TAT。。。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
typedef long long ll;
const int maxn=100007;
int i,j,k,l,n,m;
ll a[maxn],ans,ans1,t[maxn][2],yi,er,san;
int b[maxn],tou,wei;
int first[maxn*2],next[maxn*2],last[maxn*2],num,size[maxn];
int aa[maxn],bb[maxn],c[maxn],z,deep[maxn],f[maxn],g[maxn];
bool bz[maxn],az[maxn];
void add(int x,int y){
last[++num]=y;next[num]=first[x];first[x]=num;
}
void huan(int x,int y){
int i;
if(bz[x])return;
bz[x]=1;
rep(i,x){
if(last[i]!=y){
if(bz[last[i]]){
tou=x,wei=last[i];
return;
}
huan(last[i],x);
}
}
}
void dfs(int x,int y){
int i;
rep(i,x){
if(last[i]!=y){
aa[last[i]]=aa[x]+1;
dfs(last[i],x);
}
}
}
void zhao(int x,int y){
int i;size[x]=1;
rep(i,x){
if(last[i]!=y&&!az[last[i]]){
zhao(last[i],x);
size[x]+=size[last[i]];
}
}
}
void zhaozhong(int x,int y){
int i;bool dz=1;
rep(i,x){
if(last[i]!=y&&!az[last[i]]){
zhaozhong(last[i],x);
if(size[last[i]]>yi/2)dz=0;
}
}
if(yi-size[x]<=yi/2&&dz)z=x;
}
void zhaoshen(int x,int y){
f[++f[0]]=x,g[++g[0]]=x;
deep[x]=deep[y]+1;
int i;
rep(i,x){
if(last[i]!=y&&!az[last[i]]){
zhaoshen(last[i],x);
}
}
}
bool cmp(int x,int y){
return deep[x]y];
}
int lowbit(int x){
return (-x)&x;
}
void tadd(int x,int y,ll z){
int i;
for(i=x+1;i<=n;i+=lowbit(i)){
t[i][0]+=y;
t[i][1]+=z;
}
}
ll find(int x,int y){
int i;ll j=0;
for(i=x+1;i>0;i-=lowbit(i)){
j+=t[i][y];
}
return j;
}
void doing(int *x,int y){
ll i;ll k=0;
sort(x+1,x+1+x[0],cmp);
fo(i,1,x[0]){
if(aa[x[i]]x[i]]){
tadd(aa[x[i]],1,a[x[i]]);
}
k+=a[x[i]];
}
int o=x[0];
fo(i,1,x[0]){
while(o&&deep[x[i]]+deep[x[o]]>m){
if(aa[x[o]]x[o]]){
tadd(aa[x[o]],-1,-a[x[o]]);
}
k-=a[x[o--]];
}
if(!o)break;
er+=o*y;
san+=a[x[i]]*y*k;
if(o&&aa[x[i]]>bb[x[i]]){
ans-=find(m-bb[x[i]]-1,0)*y;
ans1-=a[x[i]]*find(m-bb[x[i]]-1,1)*y;
}
}
fo(i,1,o){
if(aa[x[i]]x[i]]){
tadd(aa[x[i]],-1,-a[x[i]]);
}
}
}
int get() {
char ch;
while (!isdigit(ch=getchar()));
int o=ch-48;
while (isdigit(ch=getchar())) o=o*10+ch-48;
return o;
}
void fenzhi(int x){
int i;
zhao(x,0);
yi=size[x],er=san=0;
zhaozhong(x,0);
az[z]=1;f[f[0]=1]=z;
deep[z]=0;
rep(i,z){
if(!az[last[i]]){
deep[last[i]];g[0]=0;
zhaoshen(last[i],z);
doing(g,-1);
}
}
doing(f,1);
ans+=(er-1)/2;
ans1+=(san-a[z]*a[z])/2;
rep(i,z){
if(!az[last[i]]){
fenzhi(last[i]);
}
}
}
int main(){
// freopen("pronet.in","r",stdin);
// freopen("pronet.out","w",stdout);
// freopen("fan.in","r",stdin);
n=get();m=get();
fo(i,1,n){
b[i]=get();
add(i,b[i]),add(b[i],i);
}
fo(i,1,n)a[i]=get();
huan(1,0);num=0;memset(first,0,sizeof(first));
fo(i,1,n){
if(i==tou&&b[i]==wei||i==wei&&b[i]==tou)continue;
add(i,b[i]);add(b[i],i);
}
dfs(wei,0);
memcpy(bb,aa,sizeof(bb));aa[tou]=0;
dfs(tou,0);
fenzhi(1);
fo(i,1,n){
if(aa[i]1,a[i]);
}
}
fo(i,1,n){
if(aa[i]>bb[i]){
ans+=find(m-bb[i]-1,0);
ans1+=a[i]*find(m-bb[i]-1,1);
}
}
printf("%lld %lld\n",ans,ans1);
}