题意(T1):
给你一个DAG,问1号点到某些点的必经之路的交集大小,保证1号点可到达所有点。
题解:
考试时写了树的部分分
你们来自己体会一下题解的语文造诣
UPD最终在loser的帮助下总算明白了
有环的话好像没有什么办法了啊。。。。算了我们还是原谅辣鸡出题人吧
先来一张图示
这就是题解让我们建的那棵树
这是如何建的呢?一个点连到到达ta的所有点的lca上
不难发现,这样一棵树在搜索必经之点的时候,就是要求到的点的lca到达父亲的距离
这也是不难发现的,因为作为一个必经点,ta的lca一定是ta自己
那么如何实现呢?运用类似top的方法,一边遍历一边建树
代码:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define N 50005
#define M 100005
#define sz 19
using namespace std;
int tot,nxt[M],point[N],v[M],f[N][sz],h[N],wh[N];
int in[N],hh[N];
queue<int>q;
void addline(int x,int y){++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;}
void add(int fa,int x)
{
h[x]=h[fa]+1;
f[x][0]=fa;
for (int i=1;i<sz;i++) f[x][i]=f[f[x][i-1]][i-1];
}
int lca(int x,int y)
{
if (!x) return y;if (!y) return x;
if (h[x]<h[y]) swap(x,y);
int k=h[x]-h[y];
for (int i=0;i<sz;i++)
if ((k>>i)&1) x=f[x][i];
if (x==y) return x;
for (int i=sz-1;i>=0;i--)
if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
int main()
{
freopen("attack.in","r",stdin);
freopen("attack.out","w",stdout);
int n,m,Q,i;
scanf("%d%d%d",&n,&m,&Q);
for (i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
addline(x,y);in[y]++;
}
h[1]=1;
for (i=1;i<=n;i++) if (!in[i]) q.push(i);
while (!q.empty())
{
int now=q.front(); q.pop();
for (int i=point[now];i;i=nxt[i])
{
wh[v[i]]=lca(wh[v[i]],now);
in[v[i]]--;
if (!in[v[i]]){q.push(v[i]);add(wh[v[i]],v[i]);}
}
}
while (Q--)
{
int num,fa,xx;
scanf("%d%d",&num,&fa);
for (i=2;i<=num;i++){scanf("%d",&xx);fa=lca(xx,fa);}
printf("%d\n",h[fa]);
}
}
总结:
反复检查要不要开long long
一些东西要想明白之后再修改,不然只能是画蛇添足
吐槽
联考的日常:
xp:垃圾出题人
dp:裱出题人
圆脸:spj都不会写还来出什么题
yyp:他不是保证第一个字符串比第二个字符串小吗
loser:他的字符串长度都能变成两倍了想什么呢
yq:他(题解)说的是人话吗
考试ing
喵喵喵:今天的出题人这么良心呀!(flag)
期望得分:40+100+100
实际得分:36+30+80
???我感觉还是写的很稳的???
好吧T1的40%你算成36pts我就原谅你了
你T3的原题炸我int我也忍了
你T2数组要两倍是要闹鬼咯?