Skip to main content
  1. Posts/

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

·2 mins
Note: This article is available in Chinese only. 本文暂无英文版本。 View original

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

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

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

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

具体做法是:

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

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}

Related

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

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

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

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