ZKW线段树入门

Part 1

来说说它的构造

线段树的堆式储存

这里写图片描述

我们来转成二进制看看

这里写图片描述

小学生问题:找规律

规律是很显然的

  • 一个节点的父节点是这个数左移1,这个位运算就是低位舍弃,所有数字左移一位
  • 一个节点的子节点是这个数右移1,是左节点,右移1+1是右节点
  • 同一层的节点是依次递增的,第n层有2^(n-1)个节点
  • 最后一层有多少节点,值域就是多少(这个很重要)

有了这些规律就可以开始着手建树了

  • 查询区间[1,n]

最后一层不是2的次幂怎么办? 
开到2的次幂!后面的空间我不要了!就是这么任性! 
Build函数就这么出来了!找到不小于n的2的次幂 
直接输入叶节点的信息

1 int n,M,q;int d[N<<1];
2 inline void Build(int n){
3     for(M=1;M<n;M<<=1);
4     for(int i=M+1;i<=M+n;i++) d[i]=in();
5 }

 

建完了?当然没有!父节点还都是空的呢! 

维护父节点信息? 

倒叙访问,每个节点访问的时候它的子节点已经处理过辣!

  • 维护区间和?
1 for(int i=M-1;i;--i) d[i]=d[i<<1]+d[i<<1|1];
  • 维护最值?
1 for(int i=M-1;i;--i) d[i]=max/min (d[i<<1],d[i<<1|1]);  

这样就构造出了一颗二叉树,也就是zkw线段树了! 

如果你是压行选手的话(比如我),建树的代码只需要两行。 
是不是特别Easy! 
新技能Get√

 

Part 2

单点操作

    • 单点修改
1 void Change(int x,int v){
2     d[M+x]+=v;
3 }

只是这么简单?当然不是,跟线段树一样,我们要更新它的父节点!

1 void Change(int x,int v){
2     d[x=M+x]+=v;
3     while(x) d[x>>=1]=d[x<<1]+d[x<<1|1];
4 }

没了?没了。

  • 单点查询(差分思想,后面会用到)

把d维护的值修改一下,变成维护它与父节点的差值(为后面的RMQ问题做准备) 
建树的过程就要修改一下咯!

1 void Build(int n){
2     for(M=1;M<=n+1;M<<=1);for(int i=M+1;i<=M+n;i++) d[i]=in();
3     for(int i=M-1;i;--i) d[i]=min(d[i<<1],d[i<<1|1]),d[i<<1]-=d[i],d[i<<1|1]-=d[i];
4 }

在当前情况下的查询

1 void Sum(int x,int res=0){
2     while(x) res+=d[x],x>>=1;return res;
3 }

 

Part 3 

区间操作

询问区间和,把[s,t]闭区间换成(s,t)开区间来计算

1 int Sum(int s,int t,int Ans=0){
2     for (s=s+M-1,t=t+M+1;s^t^1;s>>=1,t>>=1){
3         if(~s&1) Ans+=d[s^1];
4         if( t&1) Ans+=d[t^1];
5     }return Ans;
6 }
  • 为什么~s&1?
  • 为什么t&1?

  • 变成开区间了以后,如果s是左儿子,那么它的兄弟节点一定在区间内,同理,如果t是右儿子,那么它的兄弟节点也一定在区间内!

  • 这样计算不会重复吗?

答案是会的!所以注意迭代的出口s^t^1 
如果s,t就是兄弟节点,那么也就迭代完成了。

代码简单,即使背过也不难QuQ

    • 区间最小值
1 void Sum(int s,int t,int L=0,int R=0){
2     for(s=s+M-1,t=t+M+1;s^t^1;s>>=1,t>>=1){
3         L+=d[s],R+=d[t];
4         if(~s&1) L=min(L,d[s^1]);
5         if(t&1) R=min(R,d[t^1]);
6     }
7     int res=min(L,R);while(s) res+=d[s>>=1];
8 }

差分! 

不要忘记最后的统计! 
还有就是建树的时候是用的最大值还是最小值,这个一定要注意,影响到差分。

  • 区间最大值
1 void Sum(int s,int t,int L=0,int R=0){
2     for(s=s+M-1,t=t+M+1;s^t^1;s>>=1,t>>=1){
3         L+=d[s],R+=d[t];
4         if(~s&1) L=max(L,d[s^1]);
5         if(t&1) R=max(R,d[t^1]);
6     }
7     int res=max(L,R);while(s) res+=d[s>>=1];
8 }

同理。

  • 区间加法
1 void Add(int s,int t,int v,int A=0){
2     for(s=s+M-1,t=t+M+1;s^t^1;s>>=1,t>>=1){
3         if(~s&1) d[s^1]+=v;if(t&1) d[t^1]+=v;
4         A=min(d[s],d[s^1]);d[s]-=A,d[s^1]-=A,d[s>>1]+=A;
5         A=min(d[t],d[t^1]);d[t]-=A,d[t^1]-=A,d[t>>1]+=A;
6     }
7     while(s) A=min(d[s],d[s^1]),d[s]-=A,d[s^1]-=A,d[s>>=1]+=A;
8 }

同样是差分!差分就是厉害QuQ

zkw线段树小试牛刀(code来自hzwer.com)

 1 #include<cstdio>
 2 #include<iostream>
 3 #define M 261244
 4 using namespace std;
 5 int tr[524289];
 6 void query(int s,int t)
 7 {
 8     int ans=0;
 9     for(s=s+M-1,t=t+M+1;s^t^1;s>>=1,t>>=1)
10     {
11          if(~s&1)ans+=tr[s^1];
12          if(t&1)ans+=tr[t^1];
13          }
14     printf("%d
",ans);
15 } 
16 void change(int x,int y)
17 {
18     for(tr[x+=M]+=y,x>>=1;x;x>>=1)
19        tr[x]=tr[x<<1]+tr[x<<1|1];
20 }
21 int main()
22 {
23     int n,m,f,x,y;
24     scanf("%d",&n);
25     for(int i=1;i<=n;i++){scanf("%d",&x);change(i,x);}
26     scanf("%d",&m);
27     for(int i=1;i<=m;i++)
28     {
29             scanf("%d%d%d",&f,&x,&y);
30             if(f==1)change(x,y);
31             else query(x,y);
32             }
33     return 0;
34 }
View Code

POJ3468(code来自网络)

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cctype>
  4 #define N ((131072 << 1) + 10) //表示节点个数->不小于区间长度+2的最小2的正整数次幂*2+10
  5 typedef long long LL;
  6 inline int getc() {
  7     static const int L = 1 << 15;
  8     static char buf[L] , *S = buf , *T = buf;
  9     if (S == T) {
 10         T = (S = buf) + fread(buf , 1 , L , stdin);
 11         if (S == T)
 12             return EOF;
 13     }
 14     return *S++;
 15 }
 16 inline int getint() {
 17     static char c;
 18     while(!isdigit(c = getc()) && c != '-');
 19     bool sign = (c == '-');
 20     int tmp = sign ? 0 : c - '0';
 21     while(isdigit(c = getc()))
 22         tmp = (tmp << 1) + (tmp << 3) + c - '0';
 23     return sign ? -tmp : tmp;
 24 }
 25 inline char getch() {
 26     char c;
 27     while((c = getc()) != 'Q' && c != 'C');
 28     return c;
 29 }
 30 int M; //底层的节点数
 31 int dl[N] , dr[N]; //节点的左右端点
 32 LL sum[N]; //节点的区间和
 33 LL add[N]; //节点的区间加上一个数的标记
 34 #define l(x) (x<<1) //x的左儿子,利用堆的性质
 35 #define r(x) ((x<<1)|1) //x的右儿子,利用堆的性质
 36 void pushdown(int x) { //下传标记
 37  if (add[x]&&x<M) {//如果是叶子节点,显然不用下传标记(别忘了)
 38      add[l(x)] += add[x];
 39         sum[l(x)] += add[x] * (dr[l(x)] - dl[l(x)] + 1);
 40         add[r(x)] += add[x];
 41         sum[r(x)] += add[x] * (dr[r(x)] - dl[r(x)] + 1);
 42         add[x] = 0; 
 43     }
 44 }
 45 int stack[20] , top;//
 46 void upd(int x) { //下传x至根节点路径上节点的标记(自上而下,用栈实现)
 47  top = 0;
 48     int tmp = x;
 49     for(; tmp ; tmp >>= 1)
 50         stack[++top] = tmp;
 51     while(top--)
 52         pushdown(stack[top]);
 53 }
 54 LL query(int tl , int tr) { //求和
 55  LL res=0;
 56     int insl = 0, insr = 0; //两侧第一个有用节点
 57  for(tl=tl+M-1,tr=tr+M+1;tl^tr^1;tl>>=1,tr>>=1) {
 58         if (~tl&1) {
 59             if (!insl)
 60         upd(insl=tl^1);
 61             res+=sum[tl^1];
 62         }
 63         if (tr&1) {
 64             if(!insr)
 65         upd(insr=tl^1)
 66             res+=sum[tr^1];
 67         }
 68     }
 69     return res;
 70 }
 71 void modify(int tl , int tr , int val) { //修改
 72  int insl = 0, insr = 0;
 73     for(tl=tl+M-1,tr=tr+M+1;tl^tr^1;tl>>=1,tr>>=1) {
 74         if (~tl&1) {
 75             if (!insl)
 76                 upd(insl=tl^1);
 77             add[tl^1]+=val;
 78             sum[tl^1]+=(LL)val*(dr[tl^1]-dl[tl^1]+1);
 79         }
 80         if (tr&1) {
 81             if (!insr)
 82                 upd(insr=tr^1);
 83             add[tr^1]+=val;
 84             sum[tr^1]+=(LL)val*(dr[tr^1]-dl[tr^1]+1);
 85         }
 86     }
 87     for(insl=insl>>1;insl;insl>>=1) //一路update
 88      sum[insl]=sum[l(insl)]+sum[r(insl)];
 89     for(insr=insr>>1;insr;insr>>=1)
 90         sum[insr]=sum[l(insr)]+sum[r(insr)];
 91         
 92         
 93 }
 94 inline void swap(int &a , int &b) {
 95     int tmp = a;
 96     a = b;
 97     b = tmp;
 98 }
 99 int main() {
100     //freopen("tt.in" , "r" , stdin);
101  int n , ask;
102     n = getint();
103     ask = getint();
104     int i;
105     for(M = 1 ; M < (n + 2) ; M <<= 1);
106     for(i = 1 ; i <= n ; ++i)
107         sum[M + i] = getint() , dl[M + i] = dr[M + i] = i; //建树
108  for(i = M - 1; i >= 1 ; --i) { //预处理节点左右端点
109      sum[i] = sum[l(i)] + sum[r(i)];
110         dl[i] = dl[l(i)];
111         dr[i] = dr[r(i)];
112     }
113     char s;
114     int a , b , x;
115     while(ask--) {
116         s = getch();
117         if (s == 'Q') {
118             a = getint();
119             b = getint();
120             if (a > b)
121                 swap(a , b);
122             printf("%lld
" , query(a , b));
123         }
124         else {
125             a = getint();
126             b = getint();
127             x = getint();
128             if (a > b)
129                 swap(a , b);
130             modify(a , b , x);
131         }
132     }
133     return 0;
134 }
View Code

可持久化线段树版本(来自http://blog.csdn.net/forget311300/article/details/44306265)

 1 #include <iostream>  
 2 #include <cstdio>  
 3 #include <cstring>  
 4 #include <cmath>  
 5 #include <algorithm>  
 6 #include <vector>  
 7 #define mp(x,y) make_pair(x,y)  
 8   
 9 using namespace std;  
10   
11 const int N = 100000;  
12 const int inf = 0x3f3f3f3f;  
13   
14 int a[N + 10];  
15 int b[N + 10];  
16 int M;  
17 int lq, rq;  
18 vector<pair<int, int> > s[N * 22];  
19   
20 void add(int id, int cur)  
21 {  
22     cur += M;  
23     int lat = 0;  
24     if (s[cur].size())  
25         lat = s[cur][s[cur].size() - 1].second;  
26     s[cur].push_back(mp(id, ++lat));  
27     for (cur >>= 1; cur; cur >>= 1)  
28     {  
29         int l = 0;  
30         if (s[cur << 1].size())  
31             l = s[cur << 1][s[cur << 1].size() - 1].second;  
32         int r = 0;  
33         if (s[cur << 1 | 1].size())  
34             r = s[cur << 1 | 1][s[cur << 1 | 1].size() - 1].second;  
35         s[cur].push_back(mp(id, l + r));  
36     }  
37 }  
38   
39 int Q(int id, int k)  
40 {  
41     if (id >= M) return id - M;  
42     int l = id << 1, r = l ^ 1;  
43     int ll = lower_bound(s[l].begin(), s[l].end(), mp(lq, inf)) - s[l].begin() - 1;  
44     int rr = lower_bound(s[l].begin(), s[l].end(), mp(rq, inf)) - s[l].begin() - 1;  
45     int kk = 0;  
46     if (rr >= 0)kk = s[l][rr].second;  
47     if (ll >= 0)kk = s[l][rr].second - s[l][ll].second;  
48     if (kk < k)return Q(r, k - kk);  
49     return Q(l, k);  
50 }  
51   
52 int main()  
53 {  
54     int n, m;  
55     while (~scanf("%d%d", &n, &m))  
56     {  
57         for (int i = 0; i < n; i++)  
58         {  
59             scanf("%d", a + i);  
60             b[i] = a[i];  
61         }  
62         sort(b, b + n);  
63         int nn = unique(b, b + n) - b;  
64         for (M = 1; M < nn; M <<= 1);  
65         for (int i = 1; i < M + M; i++)  
66         {  
67             s[i].clear();  
68             //s[i].push_back(mp(0, 0));  
69         }  
70         for (int i = 0; i < n; i++)  
71         {  
72             int id = lower_bound(b, b + nn, a[i]) - b;  
73             add(i + 1, id);  
74         }  
75         while (m--)  
76         {  
77             int k;  
78             scanf("%d %d %d", &lq, &rq, &k);  
79             lq--;  
80             int x = Q(1, k);  
81             printf("%d
", b[x]);  
82         }  
83     }  
84     return 0;  
85 }  
View Code

完全模板(来自http://blog.csdn.net/forget311300/article/details/44306265)

  1 const int N = 1e5;  
  2   
  3 struct node  
  4 {  
  5     int sum, d, v;  
  6     int l, r;  
  7     void init()  
  8     {  
  9         d = 0;  
 10         v = -1;  
 11     }  
 12     void cb(node ls, node rs)  
 13     {  
 14         sum = ls.sum + rs.sum;  
 15         l = ls.l, r = rs.r;  
 16     }  
 17     int len()  
 18     {  
 19         return r - l + 1;  
 20     }  
 21     void V(int x)  
 22     {  
 23         sum = len() * x;  
 24         d = 0;  
 25         v = x;  
 26     }  
 27     void D(int x)  
 28     {  
 29         sum += len() * x;  
 30         d += x;  
 31     }  
 32 };  
 33   
 34 struct tree  
 35 {  
 36     int m, h;  
 37     node g[N << 2];  
 38     void init(int n)  
 39     {  
 40         for (m = h = 1; m < n + 2; m <<= 1, h++);  
 41         int i = 0;  
 42         for (; i <= m; i++)  
 43         {  
 44             g[i].init();  
 45             g[i].sum = 0;  
 46         }  
 47         for (; i <= m + n; i++)  
 48         {  
 49             g[i].init();  
 50             scanf("%d", &g[i].sum);  
 51             g[i].l = g[i].r = i - m;  
 52         }  
 53         for (; i < m + m; i++)  
 54         {  
 55             g[i].init();  
 56             g[i].sum = 0;  
 57             g[i].l = g[i].r = i - m;  
 58         }  
 59         for (i = m - 1; i > 0; i--)  
 60             g[i].cb(g[i << 1], g[i << 1 | 1]);  
 61     }  
 62     void dn(int x)  
 63     {  
 64         for (int i = h - 1; i > 0; i--)  
 65         {  
 66             int f = x >> i;  
 67             if (g[f].v != -1)  
 68             {  
 69                 g[f << 1].V(g[f].v);  
 70                 g[f << 1 | 1].V(g[f].v);  
 71             }  
 72             if (g[f].d)  
 73             {  
 74                 g[f << 1].D(g[f].d);  
 75                 g[f << 1 | 1].D(g[f].d);  
 76             }  
 77             g[f].v = -1;  
 78             g[f].d = 0;  
 79         }  
 80     }  
 81     void up(int x)  
 82     {  
 83         for (x >>= 1; x; x >>= 1)  
 84         {  
 85             if (g[x].v != -1)continue;  
 86             int d = g[x].d;  
 87             g[x].d = 0;  
 88             g[x].cb(g[x << 1], g[x << 1 | 1]);  
 89             g[x].D(d);  
 90         }  
 91     }  
 92     void update(int l, int r, int x, int o)  
 93     {  
 94         l += m - 1, r += m + 1;  
 95         dn(l), dn(r);  
 96         for (int s = l, t = r; s ^ t ^ 1; s >>= 1, t >>= 1)  
 97         {  
 98             if (~s & 1)  
 99             {  
100                 if (o)  
101                     g[s ^ 1].V(x);  
102                 else  
103                     g[s ^ 1].D(x);  
104             }  
105             if (t & 1)  
106             {  
107                 if (o)  
108                     g[t ^ 1].V(x);  
109                 else  
110                     g[t ^ 1].D(x);  
111             }  
112         }  
113         up(l), up(r);  
114     }  
115     int Q(int l, int r)  
116     {  
117         int ans = 0;  
118         l += m - 1, r += m + 1;  
119         dn(l), dn(r);  
120         for (int s = l, t = r; s ^ t ^ 1; s >>= 1, t >>= 1)  
121         {  
122             if (~s & 1)ans += g[s ^ 1].sum;  
123             if (t & 1)ans += g[t ^ 1].sum;  
124         }  
125         return ans;  
126     }  
127 };  
View Code

二维情况(来自http://blog.csdn.net/forget311300/article/details/44306265)

 1 #include <cstdio>  
 2 #include <algorithm>  
 3 #include <cstring>  
 4 #include <cmath>  
 5 #include <vector>  
 6 #include <iostream>  
 7   
 8 using namespace std;  
 9   
10 const int W = 1000;  
11   
12 int m;  
13   
14 struct tree  
15 {  
16     int d[W << 2];  
17     void o()  
18     {  
19         for (int i = 1; i < m + m; i++)d[i] = 0;  
20     }  
21     void Xor(int l, int r)  
22     {  
23         l += m - 1, r += m + 1;  
24         for (int s = l, t = r; s ^ t ^ 1; s >>= 1, t >>= 1)  
25         {  
26             if (~s & 1)d[s ^ 1] ^= 1;  
27             if (t & 1)d[t ^ 1] ^= 1;  
28         }  
29     }  
30   
31 } g[W << 2];  
32   
33 void chu()  
34 {  
35     for (int i = 1; i < m + m; i++)  
36         g[i].o();  
37 }  
38   
39   
40 void Xor(int lx, int ly, int rx, int ry)  
41 {  
42     lx += m - 1, rx += m + 1;  
43     for (int s = lx, t = rx; s ^ t ^ 1; s >>= 1, t >>= 1)  
44     {  
45         if (~s & 1)g[s ^ 1].Xor(ly, ry);  
46         if (t & 1)g[t ^ 1].Xor(ly, ry);  
47     }  
48 }  
49   
50 int Q(int x, int y)  
51 {  
52     int ans = 0;  
53     for (int xx = x + m; xx; xx >>= 1)  
54     {  
55         for (int yy = y + m; yy; yy >>= 1)  
56         {  
57             ans ^= g[xx].d[yy];  
58         }  
59     }  
60     return ans;  
61 }  
62   
63 int main()  
64 {  
65     int T;  
66     cin >> T;  
67     int fl = 0;  
68     while (T--)  
69     {  
70         if (fl)  
71         {  
72             printf("
");  
73         }  
74         fl = 1;  
75         int N, M;  
76         cin >> N >> M;  
77         for (m =  1; m < N + 2; m <<= 1);  
78         chu();  
79         while (M--)  
80         {  
81             char o[4];  
82             scanf("%s", o);  
83             if (*o == 'Q')  
84             {  
85                 int x, y;  
86                 scanf("%d%d", &x, &y);  
87                 printf("%d
", Q(x, y));  
88             }  
89             else  
90             {  
91                 int lx, ly, rx, ry;  
92                 scanf("%d%d%d%d", &lx, &ly, &rx, &ry);  
93                 Xor(lx, ly, rx, ry);  
94             }  
95         }  
96     }  
97     return 0;  
98 }  
View Code

非递归扫描线+离散化(来自http://blog.csdn.net/forget311300/article/details/44306265)

  1 #include <algorithm>  
  2 #include <iostream>  
  3 #include <cstdio>  
  4 #include <cstring>  
  5 #include <vector>  
  6 #include <cmath>  
  7   
  8 using namespace std;  
  9   
 10 const int N = 111;  
 11   
 12 int n;  
 13 vector<double> y;  
 14   
 15 struct node  
 16 {  
 17     double s;  
 18     int c;  
 19     int l, r;  
 20     void chu(double ss, int cc, int ll, int rr)  
 21     {  
 22         s =  ss;  
 23         c = cc;  
 24         l = ll, r = rr;  
 25     }  
 26     double len()  
 27     {  
 28         return y[r] - y[l - 1];  
 29     }  
 30 } g[N << 4];  
 31 int M;  
 32   
 33 void init(int n)  
 34 {  
 35     for (M = 1; M < n + 2; M <<= 1);  
 36     g[M].chu(0, 0, 1, 1);  
 37     for (int i = 1; i <= n; i++)  
 38         g[i + M].chu(0, 0, i, i);  
 39     for (int i = n + 1; i < M; i++)  
 40         g[i + M].chu(0, 0, n, n);  
 41     for (int i = M - 1; i > 0; i--)  
 42         g[i].chu(0, 0, g[i << 1].l, g[i << 1 | 1].r);  
 43 }  
 44   
 45 struct line  
 46 {  
 47     double x, yl, yr;  
 48     int d;  
 49     line() {}  
 50     line(double x, double yl, double yr, int dd): x(x), yl(yl), yr(yr), d(dd) {}  
 51     bool operator < (const line &cc)const  
 52     {  
 53         return x < cc.x || (x == cc.x && d > cc.d);  
 54     }  
 55 };  
 56   
 57 vector<line>L;  
 58   
 59 void one(int x)  
 60 {  
 61     if (x >= M)  
 62     {  
 63         g[x].s = g[x].c ? g[x].len() : 0;  
 64         return;  
 65     }  
 66     g[x].s = g[x].c ? g[x].len() : g[x << 1].s + g[x << 1 | 1].s;  
 67 }  
 68   
 69 void up(int x)  
 70 {  
 71     for (; x; x >>= 1)  
 72         one(x);  
 73 }  
 74   
 75 void add(int l, int r, int d)  
 76 {  
 77     if (l > r)return;  
 78     l += M - 1, r += M + 1;  
 79     for (int s = l, t = r; s ^ t ^ 1; s >>= 1, t >>= 1)  
 80     {  
 81         if (~s & 1)  
 82         {  
 83             g[s ^ 1].c += d;  
 84             one(s ^ 1);  
 85         }  
 86         if (t & 1)  
 87         {  
 88             g[t ^ 1].c += d;  
 89             one(t ^ 1);  
 90         }  
 91     }  
 92     up(l);  
 93     up(r);  
 94 }  
 95   
 96 double sol()  
 97 {  
 98     y.clear();  
 99     L.clear();  
100     for (int i = 0; i < n; i++)  
101     {  
102         double lx, ly, rx, ry;  
103         scanf("%lf %lf %lf %lf", &lx, &ly, &rx, &ry);  
104         L.push_back(line(lx, ly, ry, 1));  
105         L.push_back(line(rx, ly, ry, -1));  
106         y.push_back(ly);  
107         y.push_back(ry);  
108     }  
109     sort(y.begin(), y.end());  
110     y.erase(unique(y.begin(), y.end()), y.end());  
111     init(y.size());  
112     sort(L.begin(), L.end());  
113     n = L.size() - 1;  
114     double ans = 0;  
115     for (int i = 0; i < n; i++)  
116     {  
117         int l = upper_bound(y.begin(), y.end(), L[i].yl + 1e-8) - y.begin();  
118         int r = upper_bound(y.begin(), y.end(), L[i].yr + 1e-8) - y.begin() - 1;  
119         add(l, r, L[i].d);  
120         ans += g[1].s * (L[i + 1].x - L[i].x);  
121     }  
122     return ans;  
123 }  
124   
125 int main()  
126 {  
127     int ca = 1;  
128     while (cin >> n && n)  
129     {  
130         printf("Test case #%d
Total explored area: %.2f

", ca++, sol());  
131     }  
132     return 0;  
133 }  
View Code
原文地址:https://www.cnblogs.com/ibilllee/p/7699502.html