bzoj5329: [Sdoi2018]战略游戏【圆方树+虚树】

Description

省选临近,放飞自我的小Q无心刷题,于是怂恿小C和他一起颓废,玩起了一款战略游戏。
这款战略游戏的地图由n个城市以及m条连接这些城市的双向道路构成,并且从任意一个城市出发总能沿着道路走到
任意其他城市。现在小C已经占领了其中至少两个城市,小Q可以摧毁一个小C没占领的城市,同时摧毁所有连接这
个城市的道路。只要在摧毁这个城市之后能够找到某两个小C占领的城市u和v,使得从u出发沿着道路无论如何都不
能走到v,那么小Q就能赢下这一局游戏。
小Q和小C一共进行了q局游戏,每一局游戏会给出小C占领的城市集合S
你需要帮小Q数出有多少个城市在他摧毁之后能够让他赢下这一局游戏。

Input

第一行包含一个正整数T,表示测试数据的组数,
对于每组测试数据,
第一行是两个整数n和m,表示地图的城市数和道路数,
接下来m行,每行包含两个整数u和v~(1<=u

Output

对于每一局游戏,输出一行,包含一个整数,表示这一局游戏中有多少个城市在小Q摧毁之后能够让他赢下这一局游戏。

Sample Input

2

7 6

1 2

1 3

2 4

2 5

3 6

3 7

3

2 1 2

3 2 3 4

4 4 5 6 7

6 6

1 2

1 3

2 3

1 4

2 5

3 6

4

3 1 2 3

3 1 2 6

3 1 5 6

3 4 5 6

Sample Output

0

1

3

0

1

2

3

解题思路:

建出圆方树,答案就是虚树上圆点个数-询问端点个数。

#include<bits/stdc++.h>
#define ll long long
#define LD long double
using namespace std;
int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
    if(c=='-')c=getchar(),f=-1;
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}
const int N=100005;
int n,m,q[N];
LD x[N][2],y[N][2],Sec[N],val[N],p[N],X0,Y0,X1,Y1,L,x0;
inline bool cmp(int a,int b){return ((a>0)?x[a][0]:x[-a][1])<((b>0)?x[b][0]:x[-b][1]);}
struct line
{
    int u;
    line(int _u=0):u(_u){}
    inline friend bool operator < (const line &a,const  line &b)
    {
        if(a.u==b.u)return false;
        LD ya=(y[a.u][0]-y[a.u][1])/(x[a.u][0]-x[a.u][1])*(x0-x[a.u][0])+y[a.u][0];
        LD yb=(y[b.u][0]-y[b.u][1])/(x[b.u][0]-x[b.u][1])*(x0-x[b.u][0])+y[b.u][0];
        return abs(ya)<abs(yb);
    }
};set<line>S_up,S_down;
void solve()
{
    n=getint(),m=0;
    for(int i=1;i<=n;i++)
    {
        x[i][0]=getint(),y[i][0]=getint(),x[i][1]=getint(),y[i][1]=getint();
        Sec[i]=sqrt((x[i][0]-x[i][1])*(x[i][0]-x[i][1])+(y[i][0]-y[i][1])*(y[i][0]-y[i][1]));
    }
    X0=getint(),Y0=getint(),X1=getint(),Y1=getint(),L=getint();
    if(X0>X1)swap(X0,X1),swap(Y0,Y1);
    LD dx=X1-X0,dy=Y1-Y0,len=sqrt(dx*dx+dy*dy),Sin=dy/len,Cos=dx/len;
    for(int i=1;i<=n;i++)
    {
        x[i][0]-=X0,x[i][1]-=X0,y[i][0]-=Y0,y[i][1]-=Y0;
        LD t1,t2,t3,t4;
        t1=x[i][0]*Cos+y[i][0]*Sin,t2=y[i][0]*Cos-x[i][0]*Sin;
        t3=x[i][1]*Cos+y[i][1]*Sin,t4=y[i][1]*Cos-x[i][1]*Sin;
        x[i][0]=t1,y[i][0]=t2,x[i][1]=t3,y[i][1]=t4;
    }
    for(int i=1;i<=n;i++)
    {
        if(x[i][0]>x[i][1])swap(x[i][0],x[i][1]),swap(y[i][0],y[i][1]);
        Sec[i]/=(x[i][1]-x[i][0]);
    }
    for(int i=1;i<=n;i++)q[++m]=i,q[++m]=-i;
    sort(q+1,q+m+1,cmp);
    for(int i=1;i<=m;i++)val[i]=0;
    for(int i=1,u;i<=m;i++)
    {
        if(q[i]>0)
        {
            u=q[i];x0=p[i]=x[u][0];
            if(!S_up.empty())val[i]+=Sec[S_up.begin()->u];
            if(!S_down.empty())val[i]+=Sec[S_down.begin()->u];
            ((y[u][0]>0)?S_up:S_down).insert(line(u));
        }
        else
        {
            u=-q[i];x0=p[i]=x[u][1];
            if(!S_up.empty())val[i]+=Sec[S_up.begin()->u];
            if(!S_down.empty())val[i]+=Sec[S_down.begin()->u];
            ((y[u][0]>0)?S_up:S_down).erase(line(u));
        }
    }
    LD res=0,ans=0,l=p[1]-L,r=p[1];int pl=1,pr=2;
    while(pr<=m)
    {
        LD dl=p[pl]-l,dr=p[pr]-r;
        if(dl>dr)res+=(val[pr]-val[pl])*dr,pr++,l+=dr,r+=dr;
        else if(dl<dr)res+=(val[pr]-val[pl])*dl,pl++,l+=dl,r+=dl;
        else res+=(val[pr]-val[pl])*dl,pl++,pr++,l+=dl,r+=dl;
        ans=max(ans,res);
    }
    printf("%.15Lf\n",ans);
}
int main()
{
    freopen("laser.in","r",stdin);
    freopen("laser.out","w",stdout);
    for(int T=getint();T;T--)solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/cdsszjj/article/details/80455444