4541: [Hnoi2016]矿区

学习了一下平面图剖分的姿势,orz cbh

每次只要随便选择一条边,然后不停尽量向左转就行

#include <bits/stdc++.h>
#define N 1300000
#define M 5000013
#define LL long long
#define pb push_back
using namespace std;
LL n, m, k;
struct point
{
    LL x, y;
} S[N];
vector <LL> bi[N];
vector <LL> re[N], vis[N], s1[N], s2[N];
vector <LL> bt[N], ca[N], cb[N];
LL tot_are;
LL siz[N], sum1[N], sum2[N], tot[N];
LL nwc;
LL comp(LL a, LL b)
{
    return atan2(S[a].y - S[nwc].y, S[a].x - S[nwc].x) > atan2(S[b].y - S[nwc].y, S[b].x - S[nwc].x);
}
LL getsiz(point a, point b, point c)
{
    return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
}

namespace addr
{
    LL hs[M]; LL dt[M];
    LL get(LL a, LL b)
    {
        return 1ll * a * 1000000 + b;
    }
    LL & find(LL a, LL b)
    {
        LL p = get(a, b); LL q = p % M;
        while (hs[q] && hs[q] != p) q = (q + 1) % M;
        hs[q] = p; return dt[q];
    }
}
LL tvis[N], fa[N];
void dfs(LL t)
{
    //cout << t << "\n";

    tvis[t] = 1;
    sum1[t] = siz[t] * siz[t];
    sum2[t] = siz[t] * 2;
    for (LL i = 0; i < bt[t].size(); ++ i)
        if (!tvis[bt[t][i]])
        {
            dfs(bt[t][i]); fa[bt[t][i]] = t;
            sum1[t] += sum1[bt[t][i]];
            sum2[t] += sum2[bt[t][i]];
            s1[ca[t][i]][addr :: find(ca[t][i], cb[t][i])] = sum1[bt[t][i]];
            s2[ca[t][i]][addr :: find(ca[t][i], cb[t][i])] = sum2[bt[t][i]];
            s1[cb[t][i]][addr :: find(cb[t][i], ca[t][i])] = -sum1[bt[t][i]];
            s2[cb[t][i]][addr :: find(cb[t][i], ca[t][i])] = -sum2[bt[t][i]];
        }
}
LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
LL c = 0;
int main()
{
    //freopen("mine2.in", "r", stdin);
    n = read(); m = read(); k = read();
    for (LL i = 1; i <= n; ++ i) S[i].x = read(), S[i].y = read();
    for (LL i = 1; i <= m; ++ i)
    {
        LL a, b;
        a = read(); b = read();
        bi[a].push_back(b);
        bi[b].push_back(a);
    }
    for (LL i = 1; i <= n; ++ i) re[i].resize(bi[i].size()), s1[i] = s2[i] = vis[i] = re[i];
    for (LL i = 1; i <= n; ++ i) nwc = i, sort(bi[i].begin(), bi[i].end(), comp);
    for (LL i = 1; i <= n; ++ i)
        for (LL j = 0; j < bi[i].size(); ++ j)
            addr :: find(i, bi[i][j]) = j;
    for (LL i = 1; i <= n; ++ i)
        for (LL j = 0; j < bi[i].size(); ++ j)
            re[i][j] = addr :: find(bi[i][j], i);

    for (LL i = 1; i <= n; ++ i)
        for (LL j = 0; j < bi[i].size(); ++ j)
            if (!vis[i][j])
            {
                tot_are ++;
                for (LL k = i, p = j; !vis[k][p]; )
                {
                    siz[tot_are] += getsiz(S[i], S[k], S[bi[k][p]]);
                    vis[k][p] = tot_are;
                    LL np = (re[k][p] + 1) % bi[bi[k][p]].size();
                    k = bi[k][p];
                    p = np;
                }
                if (siz[tot_are] < 0) c = tot_are;
            }
    for (LL i = 1; i <= n; ++ i)
        for (LL j = 0; j < bi[i].size(); ++ j)
            bt[vis[i][j]].push_back(vis[bi[i][j]][re[i][j]]),
            ca[vis[i][j]].push_back(i),
            cb[vis[i][j]].push_back(bi[i][j]);
    dfs(c);
    for (LL i = 1, last = 0; i <= k; ++ i)
    {
        LL d, ns1 = 0, ns2 = 0;
        d = read(); d = (d + last) % n + 1;
        LL fs, ls, nw;
        fs = read(); fs = (fs + last) % n + 1; ls = fs;
        for (LL j = 2; j <= d; ++ j, ls = nw)
        {
            nw = read(); nw = (nw + last) % n + 1;
            ns1 += s1[ls][addr :: find(ls, nw)];
            ns2 += s2[ls][addr :: find(ls, nw)];
        }
        ns1 += s1[ls][addr :: find(ls, fs)];
        ns2 += s2[ls][addr :: find(ls, fs)];
        LL g = __gcd(ns1, ns2);
        cout << ns1 / g << " " << ns2 / g << "\n";
        last = ns1 / g;
    }
}

放在class里的东西还会爆栈QAQ,以后不敢用了

时间: 2024-08-10 21:09:43

4541: [Hnoi2016]矿区的相关文章

BZOJ 4541: [Hnoi2016]矿区 平面图转对偶图+DFS树

4541: [Hnoi2016]矿区 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 433  Solved: 182[Submit][Status][Discuss] Description 平面上的矿区划分成了若干个开发区域.简单地说,你可以将矿区看成一张连通的平面图,平面图划分为了若 干平面块,每个平面块即为一个开发区域,平面块之间的边界必定由若干整点(坐标值为整数的点)和连接这些整点 的线段组成.每个开发区域的矿量与该开发区域的面积有关:具

●BZOJ 4541 [Hnoi2016]矿区

题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4541 题解: 平面图的对偶图,dfs树 平面图的对偶图的求法: 把所有双向边拆为两条互为反向的单向边, 显然,每条单向边应该唯一属于一个平面. 我们依次枚举还没有被确定属于哪个平面的单向边, 然后从该边出发,包裹出一个最小的平面,那么途中所经过的边都属于这个平面. 包裹的具体做法: 对于当前的边x->y,我们找到其反向边y->x顺时针旋转遇到的第一条边y->z作为包裹该平面的下一条

bzoj4541 [Hnoi2016]矿区

Description 平面上的矿区划分成了若干个开发区域.简单地说,你可以将矿区看成一张连通的平面图,平面图划分为了若干平面块,每个平面块即为一个开发区域,平面块之间的边界必定由若干整点(坐标值为整数的点)和连接这些整点的线段组成.每个开发区域的矿量与该开发区域的面积有关:具体而言,面积为s的开发区域的矿量为 s^2.现在有 m 个开采计划.每个开采计划都指定了一个由若干开发区域组成的多边形,一个开采计划的优先度被规定为矿量的总和÷开发区域的面积和:例如,若某开采计划指定两个开发区域,面积分别

bzoj4541【HNOI2016】矿区

4541: [Hnoi2016]矿区 Time Limit: 30 Sec  Memory Limit: 512 MB Submit: 282  Solved: 123 [Submit][Status][Discuss] Description 平面上的矿区划分成了若干个开发区域.简单地说,你可以将矿区看成一张连通的平面图,平面图划分为了若 干平面块,每个平面块即为一个开发区域,平面块之间的边界必定由若干整点(坐标值为整数的点)和连接这些整点 的线段组成.每个开发区域的矿量与该开发区域的面积有关

BZOJ 4537: [Hnoi2016]最小公倍数

4537: [Hnoi2016]最小公倍数 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1084  Solved: 400[Submit][Status][Discuss] Description 给定一张N个顶点M条边的无向图(顶点编号为1,2,…,n),每条边上带有权值.所有权值都可以分解成2^a*3^b的形式.现在有q个询问,每次询问给定四个参数u.v.a和b,请你求出是否存在一条顶点u到v之间的路径,使得路径依次经过的边上的权值的最小公

【bzoj】4538: [Hnoi2016]网络

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4538 维护一个数据结构支持对于一颗树的操作,需要支持: 1.对于树上的一条路径上的每个点上放一个值. 2.撤销某次操作的路劲放. 3.查询除了经过这个点的路径的最大值. 往一个路径上丢值相当于往不经过条路径的所有点上丢值. 用一个树链剖分即可维护,对于操作区间取反. 直接查询单点最大值即可. 为了维护单点最大值,线段树中的每一个点对应两个堆,用于维护插入誉删除. 防止爆空间,所以标记永久

bzoj4540【HNOI2016】序列

4540: [Hnoi2016]序列 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 619  Solved: 302 [Submit][Status][Discuss] Description 给定长度为n的序列:a1,a2,-,an,记为a[1:n].类似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,-,ar- 1,ar.若1≤l≤s≤t≤r≤n,则称a[s:t]是a[l:r]的子序列.现在有q个询问,每个询问给定两个数l和r,

bzoj4539【HNOI2016】树

4539: [Hnoi2016]树 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 415  Solved: 157 [Submit][Status][Discuss] Description 小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了.开始,小A只有一棵结点数为N的树,结 点的编号为1,2,-,N,其中结点1为根:我们称这颗树为模板树.小A决定通过这棵模板树来构建一颗大树.构建过 程如下:(1)将模板树复制为初始的大树.(2)

bzoj4542【HNOI2016】大数

4542: [Hnoi2016]大数 Time Limit: 20 Sec  Memory Limit: 128 MB Submit: 801  Solved: 282 [Submit][Status][Discuss] Description 小 B 有一个很大的数 S,长度达到了 N 位:这个数可以看成是一个串,它可能有前导 0,例如00009312345 .小B还有一个素数P.现在,小 B 提出了 M 个询问,每个询问求 S 的一个子串中有多少子串是 P 的倍数(0 也 是P 的倍数).例