zoukankan      html  css  js  c++  java
  • CF223E Planar Graph

    Link
    建立这样的一个网络模型:每个点自带(1)的流量,所有流量沿着边进行流动,最后汇聚到汇点。
    也就是说每条边在某个方向上可能有流量,除了汇点以外一个点流出的流量比流入的流量大一。
    那么一个多边形(环)中的点的个数就是流出环的流量总和减去流入环的流量总和。
    我们不妨选择横坐标最小的点作为汇点。
    以汇点为根建出一棵有根生成树,那么每个点往父亲的的流量就是该点的子树大小。
    在一次询问中,我们考虑对于多边形边界上的所有点计算出它往多边形外的流量。
    注意到对于多边形边界上的一个点,把它的所有出边按极角排序,那么往多边形外走的边是一段连续的区间,预处理前缀和即可。
    总的时间复杂度为(O(n+mlog m+sum k))

    #include<map>
    #include<cmath>
    #include<cctype>
    #include<cstdio>
    #include<vector>
    #include<algorithm>
    using f64=double;
    using i64=long long;
    using pi=std::pair<int,int>;
    const int N=100007,M=200007;
    int tot=1,head[N],vis[N],sum[N],b[N];char ibuf[1<<22|1],*iS=ibuf;
    struct vec{int x,y;}a[N];struct edge{int v,w,rank,next;f64 theta;}e[M];
    std::map<pi,int>id;std::vector<int>pre[N];
    int read(){int x=0,f=1;while(isspace(*iS))++iS;if(*iS=='-')++iS,f=-1;while(isdigit(*iS))(x*=10)+=*iS++&15;return f*x;}
    void add(int u,int v){e[++tot].v=v,e[tot].next=head[u],head[u]=id[pi(u,v)]=tot;}
    int dfs(int u)
    {
        int flow=vis[u]=1;
        for(int i=head[u],f;i;i=e[i].next) if(!vis[e[i].v]) f=dfs(e[i].v),e[i].w+=f,e[i^1].w-=f,flow+=f;
        return flow;
    }
    void solve()
    {
        int k=read(),ans=k;i64 mu=0;
        for(int i=0;i<k;++i) b[i]=read();
        for(int i=0;i<k;++i) mu+=1ll*a[b[i]].x*a[b[(i+1)%k]].y-1ll*a[b[i]].y*a[b[(i+1)%k]].x;
        if(mu<0) std::reverse(b,b+k);
        for(int i=0,l,r;i<k;++i)
        {
    	l=e[id[pi(b[i],b[(i+1)%k])]].rank,r=e[id[pi(b[i],b[(i+k-1)%k])]].rank,ans+=pre[b[i]][r]-pre[b[i]][l-1];
    	if(l>r) ans+=sum[b[i]];
        }
        printf("%d
    ",ans);
    }
    int main()
    {
        fread(ibuf,1,1<<22,stdin);
        int n=read(),m=read(),root;
        for(int i=1,u,v;i<=m;++i) u=read(),v=read(),add(u,v),add(v,u);
        for(int i=1;i<=n;++i) a[i].x=read(),a[i].y=read();
        for(int i=root=1;i<=n;++i) if(a[i].x<a[root].x) root=i;
        dfs(root);
        for(int u=1;u<=n;++u)
        {
    	pre[u].push_back(0);
    	for(int i=head[u];i;i=e[i].next) pre[u].push_back(i),sum[u]+=e[i].w,e[i].theta=atan2(a[e[i].v].y-a[u].y,a[e[i].v].x-a[u].x);
    	std::sort(pre[u].begin(),pre[u].end(),[](int i,int j){return !i? 1:!j? 0:e[i].theta<e[j].theta;});
    	for(int i=1;i<(int)pre[u].size();++i) e[pre[u][i]].rank=i,pre[u][i]=pre[u][i-1]+e[pre[u][i]].w;
        }
        for(int q=read();q;--q) solve();
    }
    
  • 相关阅读:
    Xcode界面切换动画效果
    Objective—C中的排序及Compare陷阱
    串行口应用
    在windows上搭建C语言开发环境——借助eclipse和MinGW
    Leetcode--Two Sum
    C++语言笔记系列之十六——赋值兼容规则&amp;多继承的二义性
    在Powerdesigner中创建概念数据模型
    数据模型
    数据描述的三个领域
    开启PowerDesigner15工具栏上的被禁用掉的图标
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12913296.html
Copyright © 2011-2022 走看看