↓ 跳过正文
  1. Posts/

codeforces 380 C. Sereja and Brackets (线段树区间合并)

·848 字·2 分钟

题目链接 题意:给出一个由‘(’和‘)’组成的字符串。。。然后给出若干查询。。。每个查询一个区间,问区间中能匹配的括号数。。。

思路:考虑某一个区间中的括号匹配。。。其实是一个不断寻找’()‘然后删去的过程。。。

因此对于某个区间的括号匹配数。。。等于左边区间和右边区间和合法匹配数之和,再加上左区间和右区间新的能匹配到一起的括号数。

(说“因此”是因为。。。只要左边有没匹配的左括号。。。右边有没匹配的右括号。。。因为他们中间有的都是匹配好的括号,会被删除。。。所以两边的括号总能匹配在一起)

具体做法是:

线段树的节点中有三个域,分别表示,合法的括号匹配数,没有被匹配的左括号数,和没有被匹配的右括号数。

query的时候要合并左右两个区间。。。不过可能某一区间中为空。。。这里合理得初始化为node(0,0,0),就不用分情况讨论了。。。

一个和node(0,0,0)合并对原来的答案没有影响。。。。

以及,凡是需要在query的时候合并区间的问题。。。(不是那种简单的sum,min/max合并)

返回一个node会方便很多。。。。。

代码实现
 1/* ***********************************************
 2Author :111qqz
 3Created Time :Fri 23 Sep 2016 05:32:22 PM CST
 4File Name :code/cf/problem//380C.cpp
 5************************************************ */
 6#include <bits/stdc++.h>
 7#include <cstdio>
 8#include <cstring>
 9#include <iostream>
10#include <algorithm>
11#include <vector>
12#include <queue>
13#include <set>
14#include <map>
15#include <string>
16#include <cmath>
17#include <cstdlib>
18#include <ctime>
19#define fst first
20#define sec second
21#define lson l,m,rt<<1
22#define rson m+1,r,rt<<1|1
23#define ms(a,x) memset(a,x,sizeof(a))
24typedef long long LL;
25#define pi pair < int ,int >
26#define MP make_pair
27using namespace std;
28const double eps = 1E-8;
29const int dx4[4]={1,0,0,-1};
30const int dy4[4]={0,-1,1,0};
31const int inf = 0x3f3f3f3f;
32const int N=1E6+7;
33struct node
34{
35    int left,right,sum;
36    node (){}
37    node  ( int x,int y,int z): left(x),right(y),sum(z){};
38}tree[N<<2];
39char st[N];
40int n;
41void PushUp( int rt)
42{
43    int add = min(tree[rt<<1].left,tree[rt<<1|1].right);
44    tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum + add;
45    tree[rt].left = tree[rt<<1].left + tree[rt<<1|1].left - add;
46    tree[rt].right = tree[rt<<1].right + tree[rt<<1|1].right - add;
47}
48void build( int l,int r,int rt)
49{
50    if (l==r)
51    {
52	char ch = st[l-1];
53	if (ch=='(') tree[rt].left = 1;
54	else tree[rt].right = 1;
55	return;
56    }
57    int m = (l+r)>>1;
58    build(lson);
59    build(rson);
60    PushUp(rt);
61}
62node query( int L,int R,int l,int r,int rt)
63{
64    if (L<=l&&r<=R) return tree[rt];
65    int m = (l+r)>>1;
66    node res,res1,res2;
67    res = res1 = res2 = node(0,0,0); //初始为0.。。合并的时候和node(0,0,0)不会改变结果。。这样就不用分情况讨论区间了。。。大概。。(?
68    if (L<=m) res1 = query(L,R,lson);
69    if (R>=m+1) res2 = query(L,R,rson);
70    int add = min(res1.left,res2.right);
71    res.sum = res1.sum + res2.sum + add;
72    res.left = res1.left + res2.left - add;
73    res.right = res1.right + res2.right -add;
74    return res;
75}
76int m;
77int main()
78{
79#ifndef  ONLINE_JUDGE
80    freopen("code/in.txt","r",stdin);
81#endif
82    scanf("%s",st);
83    n = strlen(st);
84    ms(tree,0);
85    build(1,n,1);
86    scanf("%d",&m);
87    while (m--)
88    {
89	int x,y;
90	scanf("%d%d",&x,&y);
91	printf("%d\n",query(x,y,1,n,1).sum*2);
92    }
93#ifndef ONLINE_JUDGE
94    fclose(stdin);
95#endif
96    return 0;
97}

相关文章

poj 2886 Who Gets the Most Candies? (线段树模拟加强版约瑟夫问题+反素数)

·885 字·2 分钟
poj 2886 题目链接 题意:n 个人围成一圈,每个人身上有一个数,可正可负。从第 k 个人开始出圈,如果第 k 个人身上的数是 X,X>0,就左边第 x 个没有出圈的人出圈,否则右边第 -X 个人出圈。第 k 个人出圈得到的糖果数目为 f(k),f(x) 表示 x 的因子个数。现在问谁能拿到最多的糖果,并且拿到了多少糖果。

codeforces #609 F. Frogs and mosquitoes (线段树+二分)

·1620 字·4 分钟
题目链接 题意:n 只青蛙,第 i 只位于 x[i],舌头长度为 t[i]。m 只蚊子,第 i 只蚊子所在位置为 p[i],蚊子的大小为 b[i]。 蚊子按照出现顺序输入。 一只青蛙能吃到蚊子当且仅当蚊子和青蛙在同一个位置,或者蚊子在青蛙右边并且与青蛙的距离小于等于该青蛙舌头的长度。

codeforces 540 E. Infinite Inversions (分类思想+线段树求逆序对)

·1442 字·3 分钟
题目链接 题意:一个无穷数列,从1开始,初始第i个位置上为i,给出n个swap,每次交换两个位置的数。问交换 n 次以后得到的数列中,逆序对的个数。 思路: 官方题解: At first find the position of each element which is used in swap (using map). Now let’s find the answer. It consists of the two parts. First part is the number of inversions formed by only whose elements which took part in the swaps. They can be counted by one of the standard ways: mergesort or Fenwick tree. The second part is the number of inversions formed by pairs of elements where one element has been swapped even once, and the other element stayed at his position. Let’s consider the following test:

codeforces 515 E. Drazil and Park ( 线段树区间合并)

·886 字·2 分钟
题目链接 题意:圆上,询问任意一段弧中,任意两点的距离+两点的权值和的最大值。 思路: 1.环先拆成串,复制 1..n 到后面,变成 1..2n。 化简公式: 2 * h[u] + 2 * h[v] + dist(u, v) = 2 * h[v] + d[1] + d[2] + … + d[v-1] + 2 * h[u] - (d[1] + d[2] + … + d[u-1]).

codeforces #351 D. Jeff and Removing Periods (线段树/树状数组判断位置成等差数列)

·1339 字·3 分钟
题目链接 题意:有 n 个数,每次可以删除掉数值相同并且所在位置成等差数列(只删 2 个数或者只删 1 个数应该也是可以的),删掉这些数以后可以将剩下的数重新以任意顺序排列,称为一次操作。现在给出 m 个询问,每个询问一个区间 [l,r],问删光区间 [l,r] 中的数最少需要的操作次数。