D题
并查集搞一搞就过了
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
map<char, int > mp;
int pre[N];
int finds(int x){
return x == pre[x]? x: pre[x] = finds(pre[x]);
}
void unions(int x, int y){
int xx = finds(x);
int yy = finds(y);
pre[xx] = yy;
}
int vis[N];
int main()
{
int n;
cin >> n;
for(int i = 0 ; i <= n ;i ++) pre[i] = i;
for(int i = 1; i <= n; i ++){
string s;
cin >> s;
for(int j = 0; j < s.size(); j ++){
if(!mp[s[j]]){
mp[s[j]] = i;
}
else unions(mp[s[j]], i);
}
}
int cnt = 0;
for(int i = 1;i <= n; i ++){
int x = finds(i);
if(!vis[x]){
vis[x] = 1;
cnt ++;
}
}
cout << cnt << endl;
}
E题
线段树 区间更新 单点查询
合法的括号序列要求前缀和
>
=
0
>= 0
>=0所以查询区间最小值,如果小于0那么就是不合法的,另外第n位前缀和一定是0才合法,如果合法只需要找到最大的前缀和就行。线段树直接维护前缀和。
#include <bits/stdc++.h>
using namespace std;
#define ls rt << 1
#define rs rt << 1|1
const int N = 1e6 + 5;
typedef long long ll;
int sum[N << 2],add[N << 2],minx[N << 2], maxn[N << 2];
void pushdown(int l, int r , int rt){
if(add[rt]){
add[ls] += add[rt];
add[rs] += add[rt];
minx[rs] += add[rt];
maxn[rs] += add[rt];
minx[ls] += add[rt];
maxn[ls] += add[rt];
add[rt] = 0;
}
}
void update(int l, int r, int rt,int L, int R ,int val){
//cout << L << " " << R << " " << val << endl;
if(L <= l && r <= R){
sum[rt] += (r - l)*val;
add[rt] += val;
maxn[rt] += val;
minx[rt] += val;
return ;
}
pushdown(l, r, rt);
int mid = l + r >> 1;
if(mid >= L) update(l, mid ,ls, L, R , val);
if(mid < R) update(mid + 1, r ,rs , L ,R, val);
maxn[rt] = max(maxn[rs], maxn[ls]);
minx[rt] = min(minx[rs], minx[ls]);
}
ll queryMax(int l,int r ,int rt ,int L ,int R){
if(L <= l && r <= R){
return maxn[rt];
}
pushdown(l, r , rt);
ll ans = -100;
ll mid = l + r >> 1;
if(mid >= L) ans = max(ans, queryMax(l, mid, ls, L, R));
if(mid < R) ans = max(ans, queryMax(mid + 1, r ,rs, L, R));
return ans;
}
ll queryMin(int l, int r, int rt, int L ,int R){
if(L <= l && r <= R){
return minx[rt];
}
pushdown(l, r , rt);
ll ans = 100;
ll mid = l + r >> 1;
if(mid >= L) ans = min(ans, queryMin(l, mid, ls, L, R));
if(mid < R) ans = min(ans, queryMin(mid + 1, r ,rs, L, R));
return ans;
}
ll querySum(int l, int r, int rt ,int pos){
if(l == r){
return maxn[rt];
}
pushdown(l, r , rt);
ll ans = 0;
int mid = l + r >> 1;
if(mid >= pos) ans= querySum(l, mid, ls,pos);
if(mid < pos) ans =querySum(mid + 1, r ,rs, pos);
return ans;
}
int k[N];
int main()
{
int n;
cin >> n;
string s;
cin >> s;
int len = 1;
vector<int> ans;
int maxn1 = 0;
for(int i = 0;i < n; i ++){
if(s[i] == '('){
update(1, n , 1 , len, n , 1 - k[len]);
k[len] = 1;
}
else if(s[i] == ')'){
update(1, n , 1, len, n , -1 - k[len]);
k[len] = -1;
}
else if(s[i] == 'L'){
len --;
if(len <= 0) len = 1;
}
else if(s[i] == 'R'){
len ++;
}
else{
update(1, n ,1,len, n , -k[len]);
k[len] = 0;
}
//cout << queryMin(1, n , 1, 1, n) <<" " << querySum(1, n , 1, n) <<" " << queryMax(1, n ,1 , 1,n) << endl;
if(queryMin(1, n , 1, 1, n) >= 0 && querySum(1, n , 1, n) == 0){
ans.push_back(queryMax(1, n ,1 , 1,n));
}
else ans.push_back(-1);
}
for(int i = 0 ; i < ans.size(); i ++){
cout << ans[i] <<" ";
}
cout << endl;
}
#include <bits/stdc++.h>
using namespace std;
const int N = 5005;
std::vector<int> v[2][N];
int l[2][N], r[2][N];
int ans[2][N][N];
int sz[2][N];
int dp[N];
void dfs(int _, int x){
if(x != 1) sz[_][x] = 1;
for(int i = 0 ;i < v[_][x].size(); i ++){
int y = v[_][x][i];
dfs(_, y);
sz[_][x] += sz[_][y];
l[_][x] = min(l[_][x], l[_][y]);
r[_][x] = max(r[_][x], r[_][y]);
}
ans[_][l[_][x]][r[_][x]] = max(ans[_][l[_][x]][r[_][x]], sz[_][x]);
}
int main()
{
int n;
cin >> n;
for(int i = 0 ; i < 2; i ++){
int a;
cin >> a;
for(int j = 0; j <= a; j ++){
l[i][j] = n + 1;
r[i][j] = 0;
}
for(int j = 2; j <= a; j ++){
int x;
cin >> x;
v[i][x].push_back(j);
}
for(int j = 1; j <= n; j ++){
int x;
cin >> x;
l[i][x] = r[i][x] = j;
}
dfs(i, 1);
}
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= i; j ++){
dp[i] = max(dp[i],dp[j - 1]+max(ans[0][j][i], ans[1][j][i]));
}
}
cout << dp[n] << endl;
}