抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

这是一篇图论做法题解

闲话:我看到基本上都是动态规划做法,但我考场上第一时间想到了图论,并且个人认为图论做法更好想到一些,故写此题解。

思路

首先,容易知道对于一个点的贡献,可以认为是一定比该点小的点的个数,而在这里很容易想到可以从该点连边到比该直接点小的点(即题目描述中直接用 连接的点),而题目描述中出现若干的点值可能相等,我们可以将这些点合并为一个点并统计相同的个数,然后整体来乘比该点小的点的个数,这样可以用 的复杂度过掉此题。

方便理解,这里给出样例中最后一个的图。

具体实现

先根据题中给的大小关系建图,从大的点向小的连边相等则合并(我用的是并查集,其实也可以用缩点),然后统计子树大小总和,该点的贡献即为该点的数量乘上子树大小总和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
g++ -o2 2.cpp -o c -std=c++14
./c

*/

#include<cstdio>

using namespace std;
typedef long long ll;

const int N=5e6+100;
const int M=5e6+100;

char *p1,*p2;
char buf[100];

#define nc() getchar()
// #define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100,stdin),p1==p2)?EOF:*p1++)

inline void read(int &x){
x=0;
char ch=nc();
while(ch<48 || ch>57){
ch=nc();
}
while(ch>=48 && ch<=57){
x=(x<<3)+(x<<1)+ch-48;
ch=nc();
}
return ;
}

int tot;
int head[N];
struct edge{
int x;
int y;
int next;
}e[M];

int T;
int n,m;

int siz[N];
int cnt[N];
int son[N];
int fa[N];
int in[N];
char s[N];
int vis[N];
ll ans;

inline void init(){
tot=0;
for(int i=1;i<=n+10;i++){
siz[i]=0;
cnt[i]=1;
head[i]=-1;
fa[i]=i;
vis[i]=0;
}
return ;
}

inline void add(int x,int y){
e[tot].x=x;
e[tot].y=y;
e[tot].next=head[x];
head[x]=tot++;
return ;
}

inline int find(int x){
while(fa[x]^x)
x=fa[x];
return x;
}

inline void merge(int x,int y){
int a=find(x);
int b=find(y);
if(a!=b){
fa[b]=a;
cnt[a]+=cnt[b];
cnt[b]=0;
}
return ;
}

void dfs(int x,int fa){
siz[x]=cnt[x];
for(int i=head[x];~i;i=e[i].next){
int y=e[i].y;
if(y==fa)continue;
if(!vis[y])dfs(y,x);
siz[x]+=siz[y];
}
if(!vis[x]){
ans+=ll(cnt[x]*(siz[x]-cnt[x]));
vis[x]=1;
}
return ;
}

void debug_build(){
printf("\n");
printf("%d\n",tot);
for(int i=0;i<tot;i++){
int x=e[i].x;
int y=e[i].y;
// int w=e[i].w;
printf("%d %d\n",x,y);
}
printf("\n");
return ;
}

int main(){
read(T);
while(T--){
ans=0;
read(n);
init();
scanf("%s",s);
for(int i=1;i<n;i++){
if(s[i-1]=='='){
merge(i,i+1);
vis[i+1]=1;
}
}
for(int i=1;i<n;i++){
int x=find(i);
int y=find(i+1);
if(s[i-1]=='<')add(y,x);
else if(s[i-1]=='>')add(x,y);
}
// debug_build();
for(int i=1;i<=n;i++){
printf("%d %d \n",i,fa[i]);
}
for(int i=1;i<=n;i++){
if(!vis[i])dfs(i,0);
}
printf("%lld\n",ans);
}
return 0;
}


/*
1
13
=><<=<=>=><>

*/