[弱校胡策Round2]

出题人:LOI_DQS。

本来觉得可以AK的结果各种sb错误硬是成了160分 T_T
%yts当场AK

T1

题目大意:给定一棵树,每次选定一条链和一个点,选择链上一个点使该点到给定点路径上的边权的最大值最小。
做法:出题人说是NOIP模拟赛的题,然而我比较sb,写了LCT,大概就是每次把给定点变成根,然后求出另外两个点的LCA。
开始求LCA的地方写错了结果挂成了40wori

#include<iostream>
#include<cstdio>
using namespace std;

const int N=200005;
const int inf=1000000007;
int fa[N],tree[N][2],mx[N],val[N],q[N];
bool rev[N];
int n,m,last;

inline int read()
{
    int a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}

inline bool isroot(int x)
{
    return tree[fa[x]][0]!=x&&tree[fa[x]][1]!=x;
}

inline void pushup(int x)
{
    mx[x]=val[x];
    if (tree[x][0]) mx[x]=max(mx[x],mx[tree[x][0]]);
    if (tree[x][1]) mx[x]=max(mx[x],mx[tree[x][1]]);
}

inline void pushdown(int x)
{
    if (rev[x])
    {
        rev[x]^=1; rev[tree[x][0]]^=1; rev[tree[x][1]]^=1;
        swap(tree[x][0],tree[x][1]);
    }
}

inline void rotate(int x)
{
    int y=fa[x],z=fa[y],l=tree[y][1]==x,r=l^1;
    if (!isroot(y)) tree[z][tree[z][1]==y]=x;
    fa[x]=z; fa[y]=x; fa[tree[x][r]]=y;
    tree[y][l]=tree[x][r]; tree[x][r]=y;
    pushup(y); pushup(x);
}

inline void splay(int x)
{
    int top=0; q[++top]=x;
    for (int i=x;!isroot(i);i=fa[i])
        q[++top]=fa[i];
    while (top) pushdown(q[top--]);
    while (!isroot(x))
    {
        int y=fa[x],z=fa[y];
        if (!isroot(y))
        {
            if (tree[y][1]==x^tree[z][1]==y) rotate(x); else rotate(y);
        }
        rotate(x);
    }
}

inline void access(int x)
{
    for (last=0;x;last=x,x=fa[x])
        splay(x),tree[x][1]=last,pushup(x);
}

inline void makeroot(int x)
{
    access(x); splay(x); rev[x]^=1;
}

inline void link(int x,int y)
{
    makeroot(x); fa[x]=y;
}

inline int find(int x)
{
    splay(x);
    while (tree[x][0]) x=tree[x][0];
    return x;
}

int main()
{
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);

    n=read();
    for (int i=1;i<n;i++)
    {
        int u=read(),v=read(),w=read();
        val[i+n]=w;
        link(u,i+n); link(v,i+n);
    }
    m=read();
    for (int i=1;i<=m;i++)
    {
        int u=read(),v=read(),x=read();
        makeroot(x); access(u); access(v); 
        if (!last) puts("0");
        else access(last),splay(last),printf("%d\n",mx[last]);
    }

    fclose(stdin);
    fclose(stdout);
    return 0;
}

T2

题目大意:

i=1nj=1mf(gcd(i,j))

其中 f(i) 表示当 i 为无平方因子数时f(i)=i,否则 f(i)=0
反演一下就是
T=1nnTmTdTf(d)μ(Td)

f(x) 可以线性筛,然后总时间复杂度为 O(nlogn+Tn)
其实有线性筛的做法,可以去掉 log ,然而我不会,具体请移步 出题人blog

#include<iostream>
#include<cstdio>
using namespace std;

const int N=1500005;
int f[N],mu[N],prime[N];
bool flag[N];
long long g[N];

inline int read()
{
    int a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}

inline void pre()
{
    mu[1]=1; f[1]=1;
    for (int i=2;i<N;i++)
    {
        if (!flag[i]) {prime[++prime[0]]=i; f[i]=i; mu[i]=-1;}
        for (int j=1;j<=prime[0]&&i*prime[j]<N;j++)
        {
            flag[i*prime[j]]=1;
            if (i%prime[j]==0) {f[i*prime[j]]=0; mu[i*prime[j]]=0; break;}
            else f[i*prime[j]]=f[i]*prime[j],mu[i*prime[j]]=-mu[i];
        }
    }
    for (int i=1;i<N;i++)
        for (int j=i;j<N;j+=i)
            g[j]+=(long long)f[i]*mu[j/i];
    for (int i=1;i<N;i++)
        g[i]+=g[i-1];
}

int main()
{
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);

    pre();
    int testcase=read();
    while (testcase--)
    {
        int n=read(),m=read();
        long long ans=0;
        if (n>m) swap(n,m);
        for (int i=1,pos;i<=n;i=pos+1)
        {
            pos=min(n/(n/i),m/(m/i));
            ans+=(long long)(n/i)*(m/i)*(g[pos]-g[i-1]);
        }
        printf("%I64d\n",ans);
    }

    fclose(stdin);
    fclose(stdout);
    return 0;
}

T3

题目大意:
给定一棵trie,支持三种操作:
1.求本质不同子串个数
2.给trie上的某个节点上添加一棵子树
3.询问一个串在trie中出现的次数
做法:SAM+LCT
做法不难想,数据结构题,结果sb错误挂了。
if (fa[list[i]]!=x) 写成了 if (fa[x]!=list[i])

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int N=200010;
int n,m,id,S,tot,cnt;
int tree[N][2],ch[N][3],f[N],fa[N],q[N],len[N],w[N],tag[N],state[N];
int head[N>>1],list[N],next[N],key[N];
long long ans;
char s[N];
bool vis[N];

inline int read()
{
    int a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}

inline void insert(int x,int y,int z)
{
    next[++tot]=head[x];
    head[x]=tot;
    list[tot]=y;
    key[tot]=z;
}

inline bool isroot(int x)
{
    return tree[fa[x]][0]!=x&&tree[fa[x]][1]!=x;
}

inline void add(int x,int val)
{
    if (!x) return;
    w[x]+=val; tag[x]+=val;
}

inline void pushdown(int x)
{
    if (!tag[x]) return;
    add(tree[x][0],tag[x]); add(tree[x][1],tag[x]);
    tag[x]=0;
}

inline void rotate(int x)
{
    int y=fa[x],z=fa[y],l=tree[y][1]==x,r=l^1;
    if (!isroot(y)) tree[z][tree[z][1]==y]=x;
    fa[x]=z; fa[y]=x; fa[tree[x][r]]=y;
    tree[y][l]=tree[x][r]; tree[x][r]=y;
}

inline void splay(int x)
{
    int top=0; q[++top]=x;
    for (int i=x;!isroot(i);i=fa[i])
        q[++top]=fa[i];
    while (top) pushdown(q[top--]);
    while (!isroot(x))
    {
        int y=fa[x],z=fa[y];
        if (!isroot(y))
        {
            if (tree[y][1]==x^tree[z][1]==y) rotate(x); else rotate(y);
        }
        rotate(x);
    }
}

inline void access(int x)
{
    for (int t=0;x;t=x,x=fa[x])
        splay(x),tree[x][1]=t;
}

inline void link(int x,int f)
{
    fa[x]=f; access(f); splay(f); add(f,w[x]);
}

inline void cut(int x)
{
    access(x); splay(x); add(tree[x][0],-w[x]);
    fa[tree[x][0]]=0; tree[x][0]=0;
}

inline int extend(int last,int c)
{
    int p=last,np=++cnt;
    len[np]=len[p]+1;
    w[np]=1;
    while (p&&!ch[p][c]) ch[p][c]=np,p=f[p];
    if (!p) f[np]=S,link(np,S),ans+=len[np];
    else
    {
        int q=ch[p][c];
        if (len[p]+1==len[q]) f[np]=q,link(np,q),ans+=len[np]-len[q];
        else
        {
            int nq=++cnt;
            memcpy(ch[nq],ch[q],sizeof(ch[q]));
            len[nq]=len[p]+1;
            ans-=len[q]-len[f[q]];
            f[nq]=f[q]; link(nq,f[q]); cut(q);
            ans+=len[nq]-len[f[q]];
            f[q]=f[np]=nq; link(q,nq); link(np,nq);
            ans+=len[q]-len[nq]; ans+=len[np]-len[nq];
            while (ch[p][c]==q) ch[p][c]=nq,p=f[p];
        }
    }
    return np;
}

inline void dfs(int x)
{
    vis[x]=1;
    for (int i=head[x];i;i=next[i])
        if (!vis[list[i]])
        {
            state[list[i]]=extend(state[x],key[i]);
            dfs(list[i]);
        }
}

inline int query()
{
    int p=1,l=strlen(s);
    for (int i=0;i<l;i++)
        if (ch[p][s[i]-'a']) p=ch[p][s[i]-'a'];
        else return 0;
//  cout << p << endl;
    splay(p);
    return w[p];
}

int main()
{
    freopen("trie.in","r",stdin);
    freopen("trie.out","w",stdout);

    id=read();
    n=read();
    S=++cnt;
    for (int i=1;i<n;i++)
    {
        int u=read(),v=read(); 
        char c[5];
        scanf("%s",c);
        c[0]-='a';
        insert(u,v,c[0]); insert(v,u,c[0]);
    }
    state[1]=S;
    dfs(1);
    m=read();
    for (int i=1;i<=m;i++)
    {
        int opt=read();
        if (opt==1) printf("%I64d\n",ans);
        else if (opt==2)
        {
            int rt=read(),size=read();
            for (int j=1;j<size;j++)
            {
                int u=read(),v=read();
                char c[5];
                scanf("%s",c);
                c[0]-='a';
                insert(u,v,c[0]); insert(v,u,c[0]);
            }
            dfs(rt);
        }
        else if (opt==3)
        {
            scanf("%s",s);
            printf("%d\n",query());
        }
    }

    fclose(stdin);
    fclose(stdout);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值