[Tarjan][基环树]JZOJ 4221 互相追逐的点

Posted mastervan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Tarjan][基环树]JZOJ 4221 互相追逐的点相关的知识,希望对你有一定的参考价值。

Description

某天,某个平面上的N个点想做一个游戏。它们每个点都有一个这N个点中最喜欢的点。从某个时刻起,这N个点都向自己最喜欢的点方向以恒定的1单位/秒的速率移动,直至与它最喜欢的点距离为1或与它最喜欢的点的距离在某一秒内保持不变,在此之后它将与它最喜欢的点的运动方向保持一致。特别地,如果某时刻某个点与它最喜欢的点重叠,它这个时刻将不会移动。
现在,第N+1个点想知道这N个点做游戏的情况,但是由于它没有多少内存,你只需要告诉它经过足够长(你可以认为是无限长)的时间后任意一组不知道向哪里移动的点就可以了。一个点不知道向哪里移动,当且仅当它的移动方向只决定于它自己的移动方向,且与它自己的移动方向一致;如果一个点不知道向哪里移动,它将不再移动。
例如,如果第1个点初始在(0,0),第2个点初始在(2,0),第3个点初始在(0,2),第4个点初始在(4,0),第5个点初始在(3,6),第1个点最喜欢第2个点,第2个点最喜欢第3个点,第3个点最喜欢第1个点,第4个点最喜欢第2个点,第5个点最喜欢第4个点,那么0.1s后这5个点的坐标分别约为(0.051,0.000),(1.975,0.025),(0.001,1.949),(3.950,0.000),(3.003,5.984),0.5s后分别约为(0.279,0.010),(1.861,0.129),(0.019,1.733),(3.742,0.008),(3.012,5.918),1.0s后约为(0.655,0.061),(1.684,0.271),(0.099,1.433),(3.472,0.035),(3.020,5.833),约1.04s时第1个点与第2个点距离为1,第1个点开始与第2个点的运动方向保持一致。约1.4s时5个点坐标分别约为(0.513,0.186),(1.490,0.399),(0.210,1.139), (3.252,0.070),(3.025,5.764),第3个点与第1个点距离为1,第3个点开始与第1个点运动方向(也就是第2个点运动方向)保持一致。过了1s(即约2.4s时),5个点坐标分别约为(-0.072,0.524),(0.905,0.737),(-0.376,1.477), (2.724,0.199),(3.023,5.584),这1s内第2个点和第3个点的距离保持不变,所以第2个点开始与第3个点运动方向(也就是第2个点运动方向)保持一致。从此,第2个点不知道向哪里移动。与此同时,第1个点与第2个点运动方向也就是第3个点运动方向也就是第1个点运动方向保持一致,所以第1个点也不知道向哪里移动。第3个点与第1个点运动方向也就是第2个点运动方向也就是第3个点运动方向保持一致,所以第3个点也不知道向哪里移动。
一些不知道向哪里移动的点可以被称为“一组”,当且仅当:它们虽然不知道向哪里移动(而且不会移动),但它们如果运动则运动方向一定保持一致,而且不存在某个不属于这些点的不知道向哪里移动的点使得这些点加上这一个点仍然如果运动则运动方向一定保持一致。例如,在上述例子中第1、2、3个点可以被称为一组,而第1、2个点不能被称为一组。注意:如果一个点的移动方向只决定于一个不知道向哪里移动的点的移动方向,那么不能说这个点也不知道向哪里移动(很不科学是吧=_=)。
点忽略体积,移动时可以重叠而不互相影响。
 

Input

输入的第一行包含一个正整数N,表示点的个数。
第二行共N个正整数a1~aN,其中第i个数表示编号为i的点最喜欢的点的编号。
接下来共N行,每行两个实数xi,yi,表示编号为i的点的初始位置。由于这N个点排列得比较乱,没有任意3个点共线,没有任意两个点重叠,没有任意两个点的距离小于1。

Output

输出的第一行包含一个正整数m,表示一组不知道向哪里移动的点的个数。
第二行共m个正整数,表示这组点的编号,不要求输出顺序。
 

Sample Input

5
2 3 1 2 4
0 0
2 0
0 2
4 0
3 6

Sample Output

3
3 2 1
 

Data Constraint

对于10%的数据:1<=N<=10,xi,yi为<=10的正整数;
对于40%的数据:1<=N<=2000,xi,yi为整数;
对于60%的数据:1<=N<=20000,xi,yi为整数;
对于100%的数据:1<=N<=200000,1<=ai<=N,-10^9<=xi,yi<=10^9。

分析

这可真是浪漫的爱情故事啊

原题目名称叫做WYF互相追逐的头(有点搞笑??)

水题,基环树

把环抠出来输出

话说我都没考虑自环都A了呢

 

技术分享图片
#include <iostream>
#include <cstdio>
using namespace std;
const int N=2e5+10;
struct Edge {
    int u,v,nx;
}g[N];
int cnt,list[N],id[N];
int stack[N],low[N],dfn[N],stk[N],sz[N];
bool instk[N];
int tme,top,tp,idcnt;
int n;

void Add(int u,int v) {g[++cnt]=(Edge){u,v,list[u]};list[u]=cnt;}

void Tarjan(int v0) {
    stack[++tp]=v0;
    while (tp) {
        int u=stack[tp],i;
        if (!dfn[u]) low[u]=dfn[u]=++tme,stk[++top]=u,instk[u]=1;
        for (i=list[u];i;i=g[i].nx)
            if (!dfn[g[i].v]) break;
            else if (instk[g[i].v]) low[u]=min(low[u],dfn[g[i].v]);
        if (!i&&tp>1) low[stack[tp-1]]=min(low[stack[tp-1]],low[u]);
        if (!i) {
            if (dfn[u]==low[u]) {
                ++idcnt;
                do {
                    id[stk[top]]=idcnt;instk[stk[top]]=0;sz[idcnt]++;
                }
                while (stk[top--]!=u);
            }
            tp--;
        }
        else stack[++tp]=g[i].v;
    }
}

int main() {
    scanf("%d",&n);
    for (int i=1,v;i<=n;i++) scanf("%d",&v),Add(i,v);
    for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i);
    for (int i=1;i<=idcnt;i++) if (sz[i]>1) {
        printf("%d
",sz[i]);
        for (int j=1;j<=n;j++) if (id[j]==i) printf("%d ",j);
    }
}
View Code

 

以上是关于[Tarjan][基环树]JZOJ 4221 互相追逐的点的主要内容,如果未能解决你的问题,请参考以下文章

[语文] Jzoj P4221 互相追逐的点

骑士 HYSBZ - 1040(基环树+树形dp)

模板 - 图论 - 基环树

基环树复习

信息传递

基环树一统天下千秋万代