Powered by:AB_IN 局外人
介绍
#define lowbit(x) ((x) & -(x))
功能是找到x的二进制数的最后一个1,也就是查询前驱和后继。lowbit(6)=2
tree[x]
前面的一个点。比如6的前驱是4, t r e e [ 6 ] = a 5 + a 6 tree[6]=a_5+a_6 tree[6]=a5+a6, t r e e [ 4 ] = a 1 + a 2 + a 3 + a 4 tree[4]=a_1+a_2+a_3+a_4 tree[4]=a1+a2+a3+a4。再继续查询前驱,发现lowbit(4)=4
,那么4没有前驱,只有后继(6)。typedef long long ll;
#define lowbit(x) ((x) &-(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
inline void add(ll x,ll d)
{
while(x<=n){
tree[x]+=d;
x+=lowbit(x);//查询x的后继们
}
}
ll sum(ll x)//前缀和
{
ll sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);//查询x的前驱们
}
return sum;
}
单点更新和区间查询。
这里区间查询就是求区间和。
#include
#define lowbit(x) ((x) & -(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
int n,m,tree[2000010],t,a,b,flag;
void add(int x,int d)
{
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
}
int sum(int x)
{
int sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
cin>>n>>m;
rep(i,1,n){
cin>>t;
add(i,t);
}
rep(i,1,m){
cin>>flag>>a>>b;
if(flag==1) add(a,b);
if(flag==2) cout<<sum(b)-sum(a-1)<<endl;
}
return 0;
}
区间更新和单点查询。
涉及到差分的知识,在菜鸡之前博客有提到。
这里的单点查询是指查询这个点的值。
这个题的思路就是将原数组的差分数组放入树状数组中去。
一个点的值就是原数组那一点的值。(前缀和和差分抵消了)
#include
#define lowbit(x) ((x) & -(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
int n,m,tree[2000010],t,a,b,flag,tmp,d;
void add(int x,int d)
{
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
}
int sum(int x)
{
int sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
cin>>n>>m;
rep(i,1,n){
cin>>t;
add(i,t-tmp);
tmp=t;
}
rep(i,1,m){
cin>>flag;
if(flag==1){
cin>>a>>b>>d;
add(a,d);
add(b+1,-d);
}
if(flag==2) {cin>>a;cout<<sum(a)<<endl;}
}
return 0;
}
#include
#define lowbit(x) ((x) & -(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
int n,w,tree[2000010],x,y;
char flag;
void add(int x,int d)
{
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
}
int sum(int x)
{
int sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
cin>>n>>w;
rep(i,1,w){
cin>>flag>>x>>y;
if(flag=='x') add(x,y);
else cout<<sum(y)-sum(x-1)<<endl;
}
return 0;
}
普通做法。
#include
using namespace std;
int a[105],b[105],n;
int main()
{
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=1;i<=n;i++)
for (int j=i;j>=1;j--){
if (a[j]<a[i]) b[i]++;
}
for (int i=1;i<=n;i++) cout<<b[i]<<" ";
return 0;
}
树状数组
先去重离散化再用树状数组
去重离散化就是让每个数变成这一些数中第几小的数。
比如 1 5 8 9 3 2 1 \ 5\ 8\ 9\ 3\ 2 1 5 8 9 3 2
变成 1 4 5 6 3 2 1\ 4 \ 5 \ 6 \ 3 \ 2 1 4 5 6 3 2
然后把这一串离散化过的放入树状数组中。
add(a[i],1)
的意思就是标记这个点已经计数了,让后驱也记上数。b[i]=sum(a[i]-1)
的意思得好好想一想。
所以规律如下:
[比我小] : s u m ( a [ i ] − 1 ) sum(a[i]-1) sum(a[i]−1)
[小于等于我] : s u m ( a [ i ] ) sum(a[i]) sum(a[i])
[比我大] : i − s u m ( a [ i ] ) i-sum(a[i]) i−sum(a[i]) (逆序对)
[大于等于我] : i − s u m ( a [ i ] − 1 ) i-sum(a[i]-1) i−sum(a[i]−1)
下标是离散化后的数!!!!!
#include
#define lowbit(x) ((x) & -(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=5e5+10;
int n,a[maxn],t[maxn],tree[maxn],b[maxn];
void add(int x,int d)
{
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
}
int sum(int x)
{
int sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
long long ans;
int main()
{
cin>>n;
rep(i,1,n){
cin>>a[i];
t[i]=a[i];
}
sort(t+1,t+1+n);
int m=unique(t+1,t+1+n)-t-1;
rep(i,1,n){
a[i]=lower_bound(t+1,t+1+m,a[i])-t;
}
rep(i,1,n){
add(a[i],1);
b[i]=sum(a[i]-1);
}
rep(i,1,n) cout<<b[i]<<" ";
return 0;
}
这个题实在是不好想。
首先肯定先想到dp,设 t r e e [ i ] tree[i] tree[i]为在第i位时的方案数
t r e e [ i ] = ∑ t r e e [ j ] ( j < i , a [ i ] ≥ a [ j ] ) tree[i]=∑tree[j](jtree[i]=∑tree[j](j<i,a[i]≥a[j])
这里 t r e e tree tree是dp数组, a a a为前缀和数组。
ps:为什么这么写呢?
t r e e [ i ] tree[i] tree[i]就是 i i i之前可以怎么分组,顺着递推下去就行了。
然后看出是求在 i i i前面的并且前缀和要小于等于 a [ i ] a[i] a[i]的 t r e e [ j ] tree[j] tree[j]的和。
树状数组 维护下标为a[i],值为方案数 tree[i]的前缀和。
这里真的要好好缕一缕
还要注意的是数据有负数,所以需要离散化。
#include
#define lowbit(x) ((x) &-(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
typedef long long ll;
const int maxn = 5e5 + 5, mod = 1e9 + 9;
int n, a[maxn], b[maxn], tree[maxn];
inline void add(ll x,ll d)
{
while(x<=n){
tree[x]=(tree[x]+d)%mod;
x+=lowbit(x);//查询x的后继们
}
}
ll sum(ll x)//前缀和
{
ll sum=0;
while(x>0){
sum=(sum+tree[x])%mod;
x-=lowbit(x);//查询x的前驱们
}
return sum;
}
int main () {
cin >> n;
rep(i,1,n){
cin >> a[i];
a[i] += a[i-1];
b[i] = a[i];
}
sort(b + 1, b + n + 1);
rep(i,0,n)//注意这里是从0开始离散化,目的就是让sum[0]的地方变成最小的标号。
a[i] = lower_bound(b+1, b+n+1, a[i]) - b ;//这个地方,如果是减b,那么最小下标从1开始,如果减b加1,那么最小下标从2开始。
ll ans = 0;
add(a[0],1);//先把基准加进去。(计数dp初始化)
rep(i,1,n) {
ans = sum(a[i]);//在逆序对那说过,这就是求小于等于我的数,其实就是sum(a[i])-sum(a[i之前下标])>=0的数量
add(a[i], ans);//加上方案数
}
cout << ans << endl;
return 0;
}
其实懂了题目意思之后,这就是个板子题。
注意几个点吧:
#include
using namespace std;
typedef long long ll;
#define lowbit(x) ((x) &-(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
const int maxn=1e6+10;
int vis[maxn];
ll tree[maxn],a[maxn],id[maxn],ans[maxn];
ll n,m,l,r;
inline void add(ll x,ll d)
{
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
}
ll sum(ll x)
{
ll sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
struct sa{
int l;
int r;
int pos;
}q[maxn];
bool cmp(const struct sa &a,const struct sa &b)
{
return a.r<b.r;
}
namespace IO{
char ibuf[1<<21],*ip=ibuf,*ip_=ibuf;
char obuf[1<<21],*op=obuf,*op_=obuf+(1<<21);
inline char gc(){
if(ip!=ip_)return *ip++;
ip=ibuf;ip_=ip+fread(ibuf,1,1<<21,stdin);
return ip==ip_?EOF:*ip++;
}
inline void pc(char c){
if(op==op_)fwrite(obuf,1,1<<21,stdout),op=obuf;
*op++=c;
}
inline ll read(){
register ll x=0,ch=gc(),w=1;
for(;ch<'0'||ch>'9';ch=gc())if(ch=='-')w=-1;
for(;ch>='0'&&ch<='9';ch=gc())x=x*10+ch-48;
return w*x;
}
template<class I>
inline void write(I x){
if(x<0)pc('-'),x=-x;
if(x>9)write(x/10);pc(x%10+'0');
}
class flusher_{
public:
~flusher_(){if(op!=obuf)fwrite(obuf,1,op-obuf,stdout);}
}IO_flusher;
}
using namespace IO;
int main()
{
n=read();
rep(i,1,n){
a[i]=read();
}
m=read();
rep(i,1,m){
q[i].l=read();q[i].r=read();
q[i].pos=i;
}
sort(q+1,q+1+m,cmp);
int tmp=1;//最左
rep(i,1,m){
rep(j,tmp,q[i].r){//一开始,从左端点 -> r最小的第一组数据
if(vis[a[j]])//如果数据存在
add(id[a[j]],-1);//就在之前那个数据的下标那消去,id数组存的是下标
add(j,1);
id[a[j]]=j;//更新下标
vis[a[j]]=1;
}
tmp=q[i].r+1;//更新左端点
ans[q[i].pos]= sum(q[i].r)-sum(q[i].l-1);
}
rep(i,1,m){
write(ans[i]);
pc('\n');
}
return 0;
}
思路挺简单的,题意就是要最后的结果结果最小嘛,那么两个数列第k小的数应该一一对应才对。
那么很显然要先离散化,但是这题的坑点也就恰好在离散化。这个等会再说。
离散化之后,本题的精华就在于新建数列 c c c ,另 c [ a [ i ] ] = b [ i ] c[a[i]]=b[i] c[a[i]]=b[i]。就是说以 a [ i ] a[i] a[i]作为关键字去对 b [ i ] b[i] b[i]进行排序,那么如果是一一对应的,那么 c c c应该是升序的。
那么将原本乱的 c c c 序列升序排列的最少交换次数。这不就是归并排序的思路吗?自然而然就是求逆序对。
好了,开始回过头来写离散化,手写的去重离散化只得了10分,这就让我很吃惊……打开了评论区,发现很多都有这个问题,而且问题就在于和我用的一样的方法离散化。为了弄清本质问题,菜鸡debug了一下午……
如果您也是一样的问题,请耐心往下看:
10分的可能和本菜鸡一样用的lower_bound搭配unique的离散化。但是这样的话,两个相同的元素,它们的大小顺序是相同的。
比如我们离散化这样一组数据 3 3 5 6 8 -> 1 1 2 3 4
而我们实际需要的是 1 2 3 4 5。
其实wa9个点,有可能不是因为wa,而是因为tle了 (没看过数据,瞎猜的)
为什么呢?众所周知,这题的精华就在于新建数列, c [ a [ i ] ] = b [ i ] c[a[i] ]=b[i] c[a[i]]=b[i] 但 比如 用lower_bound+unique离散化后的数据为
a :1 1 2 3 4
b: 2 2 3 4 5
这样的话c数组是没有下标5的!!!这样在循环中 i = 5 i=5 i=5时就会绕进去,导致TLE。
所以可以选择用结构体离散化的方式,题解里基本都是这样的。
结构体离散化(序号无重复)
#include
using namespace std;
typedef long long ll;
#define lowbit(x) ((x) &-(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
const int mod=1e8-3;
const int maxn=1e5+10;
ll n,tree[maxn],c[maxn];
ll ans;
struct sa{
ll pos;
ll val;
}a[maxn],b[maxn];
inline void add(ll x,ll d)
{
while(x<=n){
tree[x]+=d;
tree[x]%=mod;
x+=lowbit(x);
}
}
ll sum(ll x)
{
ll sum=0;
while(x>0){
sum+=tree[x];
sum%=mod;
x-=lowbit(x);
}
return sum;
}
bool cmp(const struct sa &a,const struct sa &b)
{
if(a.val!=b.val) return a.val<b.val;
else return a.pos<b.pos;
}
int main()
{
cin>>n;
rep(i,1,n){
cin>>a[i].val;
a[i].pos=i;
}
rep(i,1,n){
cin>>b[i].val;
b[i].pos=i;
}
sort(a+1,a+n+1,cmp);
sort(b+1,b+n+1,cmp);
rep(i,1,n){
c[a[i].pos]=b[i].pos;
}
rep(i,1,n){
add(c[i],1);
ans=(ans+i-sum(c[i]))%mod;
}
cout<<ans<<endl;
return 0;
}
lower_bound+unique(序号有重复)
#include
using namespace std;
typedef long long ll;
#define lowbit(x) ((x) &-(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
const int mod=1e8-3;
const int maxn=1e5+10;
ll n,a[maxn],b[maxn],a_t[maxn],b_t[maxn],tree[maxn],c[maxn],pos[maxn];
ll ans;
inline void add(ll x,ll d)
{
while(x<=n){
tree[x]+=d;
tree[x]%=mod;
x+=lowbit(x);
}
}
ll sum(ll x)
{
ll sum=0;
while(x>0){
sum+=tree[x];
sum%=mod;
x-=lowbit(x);
}
return sum;
}
int main()
{
cin>>n;
rep(i,1,n){
cin>>a[i];
a_t[i]=a[i];
}
rep(i,1,n){
cin>>b[i];
b_t[i]=b[i];
}
sort(a_t+1,a_t+1+n);
sort(b_t+1,b_t+1+n);
int a_m=unique(a_t+1,a_t+1+n)-a_t-1;
int b_m=unique(b_t+1,b_t+1+n)-b_t-1;
rep(i,1,n){
a[i]=lower_bound(a_t+1,a_t+1+a_m,a[i])-a_t;
pos[a[i]] = i;
b[i]=lower_bound(b_t+1,b_t+1+b_m,b[i])-b_t;
}
rep(i,1,n) c[i]=pos[b[i]];
rep(i,1,n){
add(c[i],1);
ans=(ans+i-sum(c[i]))%mod;
}
cout<<ans<<endl;
return 0;
}
这个题一开始卡了我好久。
sort+unique
去重,这样会改变相对顺序。所以只能在输入的时候边标记边用树状数组维护,遇到重复的就不计数。#include
#define lowbit(x) ((x) & -(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=1e5+10;
typedef long long ll;
ll n,p,x,a[maxn],tree[maxn];
ll vis[maxn];
void add(ll x,ll d)
{
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
}
ll sum(ll x)
{
ll sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
ll cnt;
int main()
{
while(~scanf("%lld%lld",&n,&p)){
cnt++;
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
memset(tree,0,sizeof(tree));
printf("Case #%lld:\n",cnt);
rep(i,1,n){
scanf("%lld",&x);
if(!vis[x]) {
add(i,x);
vis[x]=1;
a[i]=sum(i);
}
else{
a[i]=a[i-1];
}
}
rep(i,1,p){
scanf("%lld",&x);
printf("%lld\n",a[x]);
}
}
return 0;
}
和小鱼比可爱类似,离散化去重即可。
#include
#define lowbit(x) ((x) & -(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=5e5+10;
int n,a[maxn],t[maxn],tree[maxn],b[maxn],p,x;
void add(int x,int d)
{
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
}
int sum(int x)
{
int sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
int cnt;
int main()
{
while(~scanf("%d%d",&n,&p)){
cnt++;
memset(a,0,sizeof(a));
memset(t,0,sizeof(t));
memset(tree,0,sizeof(tree));
rep(i,1,n){
scanf("%d",&a[i]);
t[i]=a[i];
}
sort(t+1,t+1+n);
int m=unique(t+1,t+1+n)-t-1;
rep(i,1,n){
a[i]=lower_bound(t+1,t+1+m,a[i])-t;
}
rep(i,1,n){
add(a[i],1);
b[i]=sum(a[i]-1);
}
printf("Case #%d:\n",cnt);
rep(i,1,p){
scanf("%d",&x);
printf("%d\n",b[x]);
}
}
return 0;
}
用树状数组维护两个字符串相等的数量即可。
输入用cin
然后取消同步
输出用printf
即可,比cout
取消同步要快。
#include
#define lowbit(x) ((x) & -(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=5e5+10;
int n,m,tree[maxn];
char a[maxn],b[maxn],c;
void add(int x,int d)
{
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
}
int sum(int x)
{
int sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
int cnt,op,id,p,l,r;
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>m){
cnt++;
memset(tree,0,sizeof(tree));
rep(i,1,n) cin>>a[i];
rep(i,1,n) {
cin>>b[i];
if(a[i]==b[i]) add(i,1);
}
printf("Case #%d:\n",cnt);
rep(i,1,m){
//scanf("%d",&op);
cin>>op;
if(!op) {
cin>>l>>r;
//scanf("%d%d",&l,&r);
printf("%d\n",sum(r)-sum(l-1));
}
else {
cin>>id>>p>>c;
if(id==1){
if(a[p]==b[p]&&a[p]!=c) add(p,-1);
if(a[p]!=b[p]&&b[p]==c) add(p,1);
a[p]=c;
}
if(id==2){
if(a[p]==b[p]&&b[p]!=c) add(p,-1);
if(a[p]!=b[p]&&a[p]==c) add(p,1);
b[p]=c;
}
}
}
}
return 0;
}
可以拿走的标记一下,清0即可。但并不是代表值为0的一定是拿走过的。
#include
#define lowbit(x) ((x) & -(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=5e5+10;
typedef long long ll;
ll n,m,tree[maxn],a[maxn];
int vis[maxn],cnt,op;
void add(ll x,ll d)
{
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
}
ll sum(ll x)
{
ll sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
ll l,r,x;
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>m){
cnt++;
memset(tree,0,sizeof(tree));
memset(vis,0,sizeof(vis));
rep(i,1,n) {cin>>a[i];add(i,a[i]);}
printf("Case #%d:\n",cnt);
rep(i,1,m){
cin>>op;
if(op) {
cin>>l>>r;
l++;r++;
printf("%lld\n",sum(r)-sum(l-1));
}
else {
cin>>x;
x++;
if(vis[x]) printf("Sorry\n");
else{
add(x,-a[x]);//将此处清0
vis[x]=1;
printf("%lld\n",a[x]);
}
}
}
}
return 0;
}
题目大意就是:一个星星左边和下面有多少颗星星,就是多少级别的星星。
x++
。#include
#define lowbit(x) ((x) & -(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=32010;
int n,a[maxn],tree[maxn],x,y;
void add(int x,int d)
{
while(x<=maxn){
tree[x]+=d;
x+=lowbit(x);
}
}
int sum(int x)
{
int sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
scanf("%d",&n);
rep(i,1,n){
scanf("%d%d",&x,&y);
x++;//x,y从0开始的
a[sum(x)]++;
add(x,1);
}
rep(i,0,n-1){
printf("%d\n",a[i]);
}
return 0;
}
#include
#define lowbit(x) ((x) & -(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=5e5+10;
int n,a[maxn],tree[maxn],m,p,k;
void add(int x,int d)
{
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
}
int sum(int x)
{
int sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
char op;
int main()
{
ios::sync_with_stdio(false);
cin>>n>>k;
rep(i,1,k){
cin>>op;
if(op=='A'){
cin>>m;
printf("%d\n",sum(m));
}
if(op=='B'){
cin>>m>>p;
add(m,p);
}
if(op=='C'){
cin>>m>>p;
add(m,-p);
}
}
return 0;
}
翻转相同问题可以考虑翻转的奇偶。
如果翻转次数为偶数,那么相当于没翻转。
如果翻转次数为奇数,那么相当于翻转一次。
用树状数组维护翻转次数即可。
利用差分思想进行区间更新。
#include
#define lowbit(x) ((x) & -(x))
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
using namespace std;
const int maxn=5e5+10;
int n,a[maxn],tree[maxn],m,p,l,r;
void add(int x,int d)
{
while(x<=n){
tree[x]+=d;
x+=lowbit(x);
}
}
int sum(int x)
{
int sum=0;
while(x>0){
sum+=tree[x];
x-=lowbit(x);
}
return sum;
}
namespace IO{
char ibuf[1<<21],*ip=ibuf,*ip_=ibuf;
char obuf[1<<21],*op=obuf,*op_=obuf+(1<<21);
inline char gc(){
if(ip!=ip_)return *ip++;
ip=ibuf;ip_=ip+fread(ibuf,1,1<<21,stdin);
return ip==ip_?EOF:*ip++;
}
inline void pc(char c){
if(op==op_)fwrite(obuf,1,1<<21,stdout),op=obuf;
*op++=c;
}
inline int read(){
register int x=0,ch=gc(),w=1;
for(;ch<'0'||ch>'9';ch=gc())if(ch=='-')w=-1;
for(;ch>='0'&&ch<='9';ch=gc())x=x*10+ch-48;
return w*x;
}
template<class I>
inline void write(I x){
if(x<0)pc('-'),x=-x;
if(x>9)write(x/10);pc(x%10+'0');
}
class flusher_{
public:
~flusher_(){if(op!=obuf)fwrite(obuf,1,op-obuf,stdout);}
}IO_flusher;
}
using namespace IO;
int main()
{
n=read();m=read();
rep(i,1,m){
p=read();
if(p==1){
l=read();r=read();
add(l,1);
add(r+1,-1);
}
if(p==2){
l=read();
if(sum(l)&1) printf("1\n");
else printf("0\n");
}
}
return 0;
}
完结。