T1:

  模拟题意,分析题目描述的是什么,有什么含义,发现优美具有传递性

即若存在一点想与另一点构成优美结构,则在此过程进行完成后,为了保证

所有点都具有优美结构,该点必须与另一点相连的所有点完成构成优美结构

  于是对于一点,其所需要构成的优美结构数为其所能到达的点减去其出度

问题转化为对于每个点,统计其所需要构成的优美结构数,由于给出的为一个

有向图,在无序情况下无法统计答案,考虑处理有向图的常见方法:拓扑排序

能够判断有向图是否存在环,并依据先后顺序对有向图进行排列

  在计算过程中发现一个问题为因为原图为有向图,故存在重复计算的贡献

考虑去重,发现对于一个节点,其仅对其所能到达的点作出贡献,考虑重复的

原因:存在点到达同一路径作出多余贡献。如何去重?常规手段:set,map等

stl辅助,但显然不适用,当然在最优性问题中也可以在不影响答案情况下不去重

显然也不行

  发现本问题中,重复作出的贡献指向的对象具有统一性,利用此性质,可以

对不同的对象分别建立贡献表,当贡献对象在贡献表中已经出现时,则不考虑

当次贡献

  具体实现过程是使用stl中的bitset建立贡献表,利用二进制或的性质进行贡献

(前提是本题中子节点进对父节点造成1的贡献),当然发现空间上并不允许

考虑如何优化空间复杂度,发现在或的条件下,各个节点的贡献是独立的,于是

可以利用分块的思想分别进行,降低空间复杂度,当然在当前节点造成贡献后

其不会在造成贡献,统计其本身的贡献后也可以用垃圾桶回收内存,也可以AC

代码如下:

NOIP 模拟十七_#defineNOIP 模拟十七_#include_02
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define I int
 4 #define V void
 5 const I MAXN = 6e4 + 3;
 6 const I MAXM = 1e5 + 3;
 7 I res,n,m,x,y,head[MAXN],aux[MAXN];
 8 bitset <MAXN/2> s[MAXN];
 9 struct NODE {
10     I to,nxt;
11 }node[MAXM];
12 inline V found (I x,I y) {
13     node[++head[0]].to = y,node[head[0]].nxt = head[x],head[x] = head[0];
14 }
15 namespace AOV {
16     I init[MAXN];
17     queue <I> q;
18     inline V solve (I l,I r) {
19         memcpy (init,aux,sizeof aux);
20         for (I i(1);i <= n; ++ i)
21           if (!init[i]) q.push (i);
22         while (!q.empty ()) {
23             I x(q.front ()); q.pop ();
24             res += s[x].count ();
25             if (l <= x && x <= r) s[x][x - l + 1] = 1;
26             for (I i(head[x]),y(node[i].to); i ;i = node[i].nxt,y = node[i].to) {
27               if (-- init[y] == 0) q.push (y);
28               s[y] |= s[x];
29             }
30         }
31         for (I i(1);i <= n; ++ i) s[i].reset ();
32     }
33 }
34 signed main () {
35     cin >> n >> m;
36     while (m -- ) {
37         cin >> x >> y;
38         found (y,x);
39         aux[x] ++ ;
40     }    
41     AOV :: solve (1,n/2);
42     AOV :: solve (n/2+1,n);
43     res -= head[0];
44     cout << res << endl;
45 }
View Code

T2:

  很容易想到对U与Rsort排序以保证其有序性,考虑如何匹配,发现对于当前

正在进行匹配的U,对于所有左端点小于等于其的R中,选择右端点大于等于其中

最接近的能保证最优,利用stl中的set实现查询前驱即可

代码如下:

NOIP 模拟十七_#defineNOIP 模拟十七_#include_02
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define I int
 4 const I MAXN = 5e4 + 3;
 5 I T,n,m,pos;
 6 struct Z {
 7     I ld,rd,k;
 8     friend inline bool operator < (const Z &a,const Z &b) {  return a.rd < b.rd;  }
 9 }R[MAXN],U[MAXN],aux;
10 multiset <Z> s;
11 multiset <Z> :: iterator it;
12 inline bool com (const Z &a,const Z &b) {  return a.ld < b.ld;  }
13 signed main () {
14     cin >> T;
15     while (T -- ) {
16         cin >> n >> m;
17         pos = 1;
18         for (I i(1);i <= n; ++ i)
19           cin >> U[i].ld >> U[i].rd >> U[i].k;
20         for (I i(1);i <= m; ++ i)
21           cin >> R[i].ld >> R[i].rd >> R[i].k;
22         sort (U + 1,U + n + 1,com);
23         sort (R + 1,R + m + 1,com);
24         for (I i(1);i <= n; ++ i) { 
25           while (R[pos].ld <= U[i].ld && pos <= m) s.insert (R[pos++]);
26           while (U[i].k != 0) { 
27             if ( (it = s.lower_bound (U[i])) == s.end () ) break;
28             aux = *it; s.erase (it);
29             aux.k >= U[i].k ? 
30             (aux.k -= U[i].k, U[i].k = 0) : (U[i].k -= aux.k, aux.k = 0);
31             if (aux.k) s.insert (aux);
32           }
33           if (U[i].k != 0) break;
34         }
35         pos = 1;
36         while (!U[pos].k && pos <= n) pos ++ ;
37         pos > n ? cout << "Yes" << endl : cout << "No" << endl;                                                 
38         s.clear ();
39     }
40 }
View Code