HDU 6218 Bridge

Problem :

给一个2×n的矩阵,一开始矩阵所有相邻点之间有一条边。有其、个询问,每次给出两个相邻的点的坐标,将其中的边删除或者添加,问如此操作之后整张图的割边数量。

, q<=2*10^5, 图始终保证联通。

Solution :

首先可以发现不能成为割边的边,一定被某个环所包含。因此只要维护每个环的大小即可。

若某条横边在两行中均出现了两次,才有可能构成环。用set来维护所有连续的横边。再用线段树来维护所有竖边的位置。

计算一条连续的横边产生的不能成为割边的数量,统计其中最左和最右的竖边以及竖边的数量就行了。

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 8;
const int INF = 1e9 + 7; #define endl "\n"
#define y1 qqq
struct node
{
int l, r;
node(){}
node(int l, int r):l(l),r(r){}
bool operator < (const node &b) const
{
return l < b.l;
}
};
multiset <node> S;
int n, q, mtot, num;
int cnt[N];
class Segment_Tree
{
public:
int tagmin[N << 2], tagmax[N << 2], tagsum[N << 2];
void pushup(int rt)
{
tagmin[rt] = min(tagmin[rt << 1], tagmin[rt << 1 | 1]);
tagmax[rt] = max(tagmax[rt << 1], tagmax[rt << 1 | 1]);
tagsum[rt] = tagsum[rt << 1] + tagsum[rt << 1 | 1];
}
void build(int l, int r, int rt)
{
tagmin[rt] = INF; tagmax[rt] = 0; tagsum[rt] = 0;
if (l == r)
{
tagmin[rt] = tagmax[rt] = l;
tagsum[rt] = 1;
return;
}
int m = l + r >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
pushup(rt);
}
void update(int x, int op, int l, int r, int rt)
{
if (l == r)
{
if (op == 1)
{
tagmin[rt] = tagmax[rt] = l; tagsum[rt] = 1;
}
else
{
tagmin[rt] = INF; tagmax[rt] = 0; tagsum[rt] = 0;
}
return;
}
int m = l + r >> 1;
if (x <= m) update(x, op, l, m, rt << 1);
else update(x, op, m + 1, r, rt << 1 | 1);
pushup(rt);
}
void querymax(int L, int R, int l, int r, int rt, int &ans)
{
if (L <= l && r <= R)
{
ans = max(ans, tagmax[rt]);
return;
}
int m = l + r >> 1;
if (L <= m) querymax(L, R, l, m, rt << 1, ans);
if (m < R) querymax(L, R, m + 1, r, rt << 1 | 1, ans);
}
void querymin(int L, int R, int l, int r, int rt, int &ans)
{
if (L <= l && r <= R)
{
ans = min(ans, tagmin[rt]);
return;
}
int m = l + r >> 1;
if (L <= m) querymin(L, R, l, m, rt << 1, ans);
if (m < R) querymin(L, R, m + 1, r, rt << 1 | 1, ans);
}
void querysum(int L, int R, int l, int r, int rt, int &ans)
{
if (L <= l && r <= R)
{
ans += tagsum[rt];
return;
}
int m = l + r >> 1;
if (L <= m) querysum(L, R, l, m, rt << 1, ans);
if (m < R) querysum(L, R, m + 1, r, rt << 1 | 1, ans);
}
}T;
int calc(int l, int r)
{
int L = INF, R = -INF, sum = 0;
T.querymin(l, r, 1, n, 1, L);
T.querymax(l, r, 1, n, 1, R);
T.querysum(l, r, 1, n, 1, sum);
if (sum <= 1) return 0;
return (R - L) * 2 + sum;
}
void init()
{
cin >> n >> q;
T.build(1, n, 1);
S.clear();
for (int i = 1; i <= n; ++i) cnt[i] = 2;
S.insert(node(1, n));
S.insert(node(-1, -1));
S.insert(node(n + 2, n + 2));
mtot = 3 * n - 2;
num = calc(1, n);
}
void work_row_add(int x)
{
auto l = S.upper_bound(node(x, x + 1)); l--;
auto r = S.lower_bound(node(x, x + 1));
cnt[x]++; mtot++;
if (cnt[x] == 1)
{
cout << mtot - num << endl;
return;
}
if (l->r == x && r->l == x + 1)
{
num -= calc(l->l, l->r);
num -= calc(r->l, r->r);
num += calc(l->l, r->r);
S.insert(node(l->l, r->r));
S.erase(l);
S.erase(r);
}
else if (l->r == x && r->l != x + 1)
{
num -= calc(l->l, l->r);
num += calc(l->l, x + 1);
S.insert(node(l->l, x + 1));
S.erase(l);
}
else if (l->r != x && r->l == x + 1)
{
num -= calc(r->l, r->r);
num += calc(x, r->r);
S.insert(node(x, r->r));
S.erase(r);
}
else if (l->r != x && r->l != x + 1)
{
num += calc(x, x + 1);
S.insert(node(x, x + 1));
}
}
void work_row_del(int x)
{
auto p = S.upper_bound(node(x, x + 1)); p--;
cnt[x]--; mtot--;
if (cnt[x] == 0) return;
if (p->l == x && p->r == x + 1)
{
num -= calc(x, x + 1);
S.erase(p);
}
else if (p->l == x && p->r != x + 1)
{
num += calc(x+1,p->r);
num -= calc(p->l,p->r);
S.insert(node(x+1,p->r));
S.erase(p);
}
else if (p->l != x && p->r == x + 1)
{
num += calc(p->l,x);
num -= calc(p->l,p->r);
S.insert(node(p->l,x));
S.erase(p);
}
else if (p->l != x && p->r != x + 1)
{
num -= calc(p->l, p->r);
num += calc(p->l, x);
num += calc(x+1, p->r);
S.insert(node(p->l, x));
S.insert(node(x+1, p->r));
S.erase(p);
}
}
void work_col_add(int x)
{
auto p = S.upper_bound(node(x, x)); p--;
mtot++;
if (p->r >= x)
{
num -= calc(p->l, p->r);
T.update(x, 1, 1, n, 1);
num += calc(p->l, p->r);
}
else
{
T.update(x, 1, 1, n, 1);
}
}
void work_col_del(int x)
{
auto p = S.upper_bound(node(x, x)); p--;
mtot--;
if (p->r >= x)
{
num -= calc(p->l, p->r);
T.update(x, -1, 1, n, 1);
num += calc(p->l, p->r);
}
else
{
T.update(x, -1, 1, n, 1);
}
}
void solve()
{
for (; q; --q)
{
int op, x1, y1, x2, y2;
cin >> op >> x1 >> y1 >> x2 >> y2; if (y1 > y2) swap(y1, y2);
if (op == 1)
if (x1 == x2) work_row_add(y1);
else work_col_add(y1);
else
if (x1 == x2) work_row_del(y1);
else work_col_del(y1);
cout << mtot - num << endl;
}
}
int main()
{
cin.sync_with_stdio(0);
int T; cin >> T;
for (int cas = 1; cas <= T; ++cas)
{
init();
solve();
}
}

HDU 6218 (线段树+set)的更多相关文章

  1. hdu 5877 线段树(2016 ACM/ICPC Asia Regional Dalian Online)

    Weak Pair Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total ...

  2. hdu 3974 线段树 将树弄到区间上

    Assign the task Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  3. hdu 3436 线段树 一顿操作

    Queue-jumpers Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) To ...

  4. hdu 3397 线段树双标记

    Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  5. hdu 4578 线段树(标记处理)

    Transformation Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 65535/65536 K (Java/Others) ...

  6. hdu 4533 线段树(问题转化+)

    威威猫系列故事——晒被子 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Tot ...

  7. hdu 2871 线段树(各种操作)

    Memory Control Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  8. hdu 4052 线段树扫描线、奇特处理

    Adding New Machine Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  9. hdu 1542 线段树扫描(面积)

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

随机推荐

  1. Js笔记-第17课

    课 // 作业 //深度拷贝 var obj = { name:'rong', age:'25', card:['visa','alipay'], nam :['1','2','3','4','4'] ...

  2. Spring中使用事务搭建转账环境方法二 相对简便的注解方法 ——配置文件注入对象属性需要setter方法 注解方法,不需要生成setter方法

    XML配置文件代码如下: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=" ...

  3. 解决windows系统下打开应用弹出丢失libmysql.dll的问题

    只要把下载libmysql.dll,放到exe应用程序的所在目录,就可以运行,libmysql.dll有32位和64位版本,可以分别测试一下行不行,如果不行在换一个 版本试试.libmysql.dll ...

  4. iOS 设置随意屏幕旋转

    方法一,通过控制器继承或分类实现: 在UITabBarController 的子类或分类中实现 - (BOOL)shouldAutorotate { return [self.selectedView ...

  5. cocos2d-x中的字符串操作

    1:循环体中字符串的构造.      通常用于多个有规律的文件的名字,诸如:[NSString stringWithFormat:@"filed.png",i].我们可以通过spr ...

  6. Where do I belong-freecodecamp算法题目

    Where do I belong(数组排序并找出元素索引) 要求 给数组排序 找到指定的值在数组的位置,并返回位置对应的索引. 思路 设定.sort()需要的返回函数 将要搜索的值添加到数组内 用. ...

  7. Ajax原生代码

    Ajax传数据有两种方式:get/post.下面是前台的get/post方式的代码. //------------原生--------- function AjaxGET(){ //第一步 调用Aja ...

  8. 在Unix系统上,从源文件、目标文件、可执行文件的编译过程

    是由“编译器驱动”(compiler driver)完成的: unix> gcc -o hello hello.c 在这里,gcc的编译器驱动程序读取源文件hello.c, #include & ...

  9. ASCII码表含义

    在计算机中,所有的数据在存储和运算时都要使用二进制数表示(因为计算机用高电平和低电平分别表示1和0),例如,像a.b.c.d这样的52个字母(包括大写)以及0.1等数字还有一些常用的符号(例如*.#. ...

  10. poj 3280 回文字符串问题 dp算法

    题意:给一个字符串,构成回文(空也是回文) 其中增删都需要代价.问:代价最少? 思路:把字符串s变空  dp[i][j]表示变成回文的最小代价 for(i=m-1;i>=0;--i)       ...