bzoj 3091 城市旅行 - LCT

13 篇文章 0 订阅

暴力碾标算系列
写一个时间复杂度基于直径长度的算法可以获得一百分的好成绩。
暴力(后面有std代码):

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 50010
#define lint long long
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
int fa[N],l[N];lint a[N];
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
inline lint gcd(lint x,lint y) { return x?gcd(y%x,x):y; }
inline int Makeroot(int x,int c=0)
{
    for(int y=x;y;y=fa[y]) l[++c]=y;
    for(;c;c--) fa[l[c]]=l[c-1];return 0;
}
inline int Getfa(int x) { while(fa[x]) x=fa[x];return x; }
inline int Link(int x,int y)
{
    int c=0,z=y;Makeroot(x);
    return Getfa(y)==x?0:fa[x]=y;
}
inline int Cut(int x,int y)
{
    if(fa[x]==y) return fa[x]=0;
    if(fa[y]==x) return fa[y]=0;
    return 0;
}
inline int Update(int x,int y,int d)
{
    Makeroot(x);if(Getfa(y)!=x) return 0;
    while(y) a[y]+=d,y=fa[y];return 0;
}
inline int Query(int x,int y)
{
    Makeroot(x);int c=0;while(y) l[++c]=y,y=fa[y];
    if(l[c]!=x) return !printf("-1\n");lint ans=0,t=c*(c+1ll)/2;
    for(int i=1;i<=c;i++) ans+=a[l[i]]*i*(c-i+1);
    lint d=gcd(ans,t);return !printf("%lld/%lld\n",ans/d,t/d);
}
int main()
{
    int n=inn(),m=inn();
    for(int i=1;i<=n;i++) a[i]=inn();
    for(int i=1;i<n;i++) Link(inn(),inn());
    while(m--)
    {
        int opt=inn(),x=inn(),y=inn();
        if(opt==1) Cut(x,y);
        if(opt==2) Link(x,y);
        if(opt==3) Update(x,y,inn());
        if(opt==4) Query(x,y);
    }
    return 0;
}

std:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 50010
#define lint long long
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
int ch[N][2],fa[N],rev[N],sz[N],pf[N];
lint val[N],s[N],ss[N],ps[N],ans[N],pt[N];
inline lint gcd(lint x,lint y) { return x?gcd(y%x,x):y; }
inline int gw(int x) { return ch[fa[x]][1]==x; }
inline lint init(int x,int v) { return val[x]=s[x]=ss[x]=ps[x]=ans[x]=v; }
inline int update_tags(int x,lint d)
{
    s[x]+=sz[x]*d,pt[x]+=d,val[x]+=d,
    ps[x]+=sz[x]*(sz[x]+1ll)/2*d,
    ss[x]+=sz[x]*(sz[x]+1ll)/2*d,
    ans[x]+=sz[x]*(sz[x]+1ll)/2*(sz[x]+2ll)/3*d;
    return 0;
}
inline int push_down(int x)
{
    if(rev[x])
    {
        if(ch[x][0]) ch[x][0][rev]^=1;
        if(ch[x][1]) ch[x][1][rev]^=1;
        swap(ch[x][0],ch[x][1]),rev[x]=0,
        swap(ps[x],ss[x]);
    }
    if(pt[x])
    {
        if(ch[x][0]) update_tags(ch[x][0],pt[x]);
        if(ch[x][1]) update_tags(ch[x][1],pt[x]);
        pt[x]=0;
    }
    return 0;
}
inline int push_up(int x)
{
    int lc=ch[x][0],rc=ch[x][1];push_down(lc),push_down(rc);
    x[ans]=lc[ans]+rc[ans]+lc[ss]*(rc[sz]+1ll)+rc[ps]*(lc[sz]+1ll)+x[val]*(lc[sz]+1ll)*(rc[sz]+1ll),
    x[ps]=lc[ps]+rc[ps]+(lc[s]+x[val])*(sz[rc]+1ll),x[ss]=rc[ss]+lc[ss]+(rc[s]+x[val])*(lc[sz]+1ll),
    x[s]=lc[s]+rc[s]+x[val],x[sz]=lc[sz]+rc[sz]+1;return 0;
}
inline int setc(int x,int y,int z)
{
    if(!x) return fa[y]=0;
    ch[x][z]=y;if(y) fa[y]=x;
    return push_up(x);
}
inline int rotate(int x)
{
    int y=fa[x],z=fa[y],a=gw(x),b=gw(y),c=ch[x][a^1];
    return swap(pf[x],pf[y]),setc(y,c,a),setc(x,y,a^1),setc(z,x,b);
}
inline int all_down(int x) { return (fa[x]?all_down(fa[x]):0),push_down(x); }
inline int splay(int x,int tar=0)
{
    for(all_down(x);fa[x]^tar;rotate(x))
        if(fa[fa[x]]^tar) rotate(gw(x)==gw(fa[x])?fa[x]:x);
    return 0;
}
inline int expose(int x)
{
    splay(x);int y=ch[x][1];if(!y) return 0;
    return pf[y]=x,ch[x][1]=fa[y]=0,push_up(x);
}
inline int splice(int x)
{
    splay(x);int y=pf[x];if(!y) return 0;
    return expose(y),splay(y),setc(y,x,1),pf[x]=0,1;
}
inline int access(int x) { expose(x);while(splice(x));return 0; }
inline int evert(int x) { return access(x),splay(x),rev[x]^=1; }
inline int get_rt(int x)
{
    access(x),splay(x);
    while(ch[x][0]) push_down(x=ch[x][0]);
    return splay(x),x;
}
inline int con(int x,int y) { return get_rt(x)==get_rt(y); }
inline int link(int x,int y) { return (!con(x,y))?evert(x),pf[x]=y:0; }
inline int cut(int x,int y)
{
    evert(x),access(y),splay(x);
    if(ch[x][1]==y) pf[y]=fa[y]=ch[x][1]=0,push_up(x);
    return 0;
}
inline int update(int x,int y,int d)
{
    if(!con(x,y)) return 0;
    return evert(x),access(y),splay(x),update_tags(x,d);
}
inline int query(int x,int y)
{
    if(!con(x,y)) return !printf("-1\n");
    evert(x),access(y),splay(x);
    lint t=sz[x]*(sz[x]+1ll)/2,d=gcd(ans[x],t);
    return !printf("%lld/%lld\n",ans[x]/d,t/d);
}
int main()
{
    int n=inn(),m=inn();
    for(int i=1;i<=n;i++) init(i,inn());
    for(int i=1;i<n;i++) link(inn(),inn());
    while(m--)
    {
        int opt=inn(),x=inn(),y=inn();
        if(opt==1) cut(x,y);
        if(opt==2) link(x,y);
        if(opt==3) update(x,y,inn());
        if(opt==4) query(x,y);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值