出题人: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=1n∑j=1mf(gcd(i,j))
其中 f(i) 表示当 i 为无平方因子数时
反演一下就是
∑T=1n⌊nT⌋⌊mT⌋∑d∣Tf(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;
}