Ynoi2011题解

d1t1 初始化

题意

一个长度为 \(n\) 的序列,\(q\) 次操作。

  • 询问 \([l,r]\) 的区间和。
  • 将所有 \(\bmod x=y\) 的下标位置加 \(z\)

\(n,q\leq 2\times 10^5\)

题解

考虑根号分治。

  • \(x>\sqrt n\),修改位置不超过 \(\sqrt n\),暴力修改,利用分块维护来平衡复杂度。
  • \(x<\sqrt n\),对于一个询问,把序列按照 \(x\) 分块,中间是一些整块,两边是一个前缀和后缀和的形式,直接用 \(tag(x,y)\) 表示 \((x,y)\) 的操作中 \(z\) 的总和是多少,然后每次暴力算一下 \(x\) 关于 \(y\) 的前缀和后缀和即可
点击查看代码
#include <bits/stdc++.h>

using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;
typedef double db;

# define chkmax(a,b) a=max(a,b)
# define chkmin(a,b) a=min(a,b)
# define PII pair<int,int>
# define mkp make_pair

const int N=2e5+5;
const int M=505;
const int mod=1e9+7;

template<typename T> void read(T &x){
    x=0;int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

int n,m,B,bl;
int a[N];
int pos[N],L[N],R[N];
int val[N],sum[M];
int g[M][M];

# define tas(x,y) (x=x+y>=mod?x+y-mod:x+y)

int main()
{
    read(n),read(m);
    B=sqrt(n)+1;
    Rep(i,1,n)read(a[i]);
    bl=(n-1)/B+1;
    Rep(i,1,bl)L[i]=(i-1)*B+1,R[i]=i*B;
    R[bl]=n;
    Rep(i,1,n)pos[i]=(i-1)/B+1;
    Rep(i,1,n)val[i]=a[i],tas(sum[pos[i]],a[i]);
    while(m--){
        int opt,x,y,z;
        read(opt),read(x),read(y);
        if(opt==1){
            read(z);
            if(x>B)for(;y<=n;y+=x)tas(val[y],z),tas(sum[pos[y]],z);
            else Rep(i,y,x)tas(g[x][i],z);
        }
        else{
            ll ans=0;
            if(pos[x]==pos[y])Rep(i,x,y)ans+=val[i];
            else{
                for(int i=pos[x]+1;i<pos[y];i++)ans+=sum[i];
                Rep(i,x,R[pos[x]])ans+=val[i];
                Rep(i,L[pos[y]],y)ans+=val[i];
            }
            Rep(i,1,B){
                int pl=(x-1)/i;
                int pr=(y-1)/i;
                if(pl==pr)ans+=g[i][(y-1)%i+1]-g[i][(x-1)%i];
                else{
                    ans+=1ll*(pr-pl-1)*g[i][i]%mod;
                    ans+=g[i][i]-g[i][(x-1)%i];
                    ans+=g[i][(y-1)%i+1];
                }
            }
            ans%=mod;
            printf("%lld\n",tas(ans,mod));
        }
    }
    return 0;
}

d1t2 遥远的过去

题意

有两个所有字符各不相同的字符串 \(A,B,|A|=n,|B|=m\),定义两个字符串匹配当且仅当他们长度相同,并且他们的字符离散化之后相同。现在 \(q\) 次修改 \(B\) 中的一个位置,询问修改后的 \(B\) 作为子串在 \(A\) 中的匹配次数。
\(n,m,q\leq 10^5,m\leq n\)

题解

考虑一个哈希:\(hash(S)=\sum_{i=1}^n base^ipos_i\),其中 \(pos_i\)\(S\) 中第 \(i\) 大的字符所在的位置。
那么先预处理出 \(A\) 中所有的长度为 \(m\) 的子串的哈希值,扔到哈希表里,然后利用平衡树快速维护每次修改之后 \(B\) 的哈希值

点击查看代码
#include <bits/stdc++.h>

using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

const int N=1e5+5;
const int base=1145141;

# define ll long long
# define db double
# define ull unsigned long long
# define uint unsigned int
# define chkmax(a,b) a=max(a,b)
# define chkmin(a,b) a=min(a,b)
# define mkp make_pair
# define PII pair<int,int>
# define PLL pair<ll,ll>
# define PIL pair<int,ll>
# define PLI pair<ll,int>

template<typename T> void read(T &x){
    x=0;int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

int n,m,q;
int a[N],b[N];
int siz[N],son[N][2],treap[N],val[N];
int rt;
ull ha[N],poww[N];
mt19937 rnd(time(0));

struct myhash{
    const int mod=19260817;
    int head[20000005],cnt;
    struct Edge{
        ull to;
        int next,cnt;
    }e[N<<2];
    void ins(ull x){
        int y=x%mod;
        for(int i=head[y];i;i=e[i].next)
            if(e[i].to==x){e[i].cnt++;return;}
        e[++cnt]=(Edge){x,head[y],1},head[y]=cnt;
    }
    int ask(ull x){
        int y=x%mod;
        for(int i=head[y];i;i=e[i].next)
            if(e[i].to==x)return e[i].cnt;
        return 0;
    }
}var;

void update(int x){
    siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
    ha[x]=ha[son[x][0]]+x*poww[siz[son[x][0]]]+ha[son[x][1]]*poww[siz[son[x][0]]+1];
}

int merge(int u,int v){
    if(!u||!v)return u|v;
    int rt;
    if(treap[u]<treap[v])son[rt=u][1]=merge(son[u][1],v);
    else son[rt=v][0]=merge(u,son[v][0]);
    return update(rt),rt;
}

void split(int o,int &u,int &v,int k){
    if(!o){u=v=0;return;}
    if(val[o]<=k)split(son[u=o][1],son[o][1],v,k);
    else split(son[v=o][0],u,son[o][0],k);
    update(o);
}

void insert(int x){
    int lft,rht;
    split(rt,lft,rht,val[x]);
    update(x);
    rt=merge(merge(lft,x),rht);
}

void erase(int x){
    int lft,mid,rht;
    split(rt,lft,rht,val[x]);
    split(lft,lft,mid,val[x]-1);
    son[x][0]=son[x][1]=0;
    val[x]=ha[x]=0;
    rt=merge(lft,rht);
}

int main()
{
    # ifndef ONLINE_JUDGE
    freopen("testdata.in","r",stdin);
    //freopen("test1.out","w",stdout);
    # endif
    read(n),read(m),read(q);
    Rep(i,1,n)read(a[i]);
    Rep(i,1,m)read(b[i]);
    poww[0]=1;
    Rep(i,1,n)poww[i]=poww[i-1]*base,treap[i]=rnd();
    ull d=0;
    Rep(i,1,m)val[i]=a[i],insert(i),d+=poww[i-1];
    Rep(i,m,n){
        var.ins(ha[rt]-d*(i-m));
        erase(i-m+1);
        if(i==n)break;
        val[i+1]=a[i+1];
        insert(i+1);
    }
    rt=0;
    memset(son,0,sizeof(son));
    memset(ha,0,sizeof(ha));
    Rep(i,1,m)val[i]=b[i],insert(i);
    while(q--){
        int x,y;
        read(x),read(y);
        erase(x);
        val[x]=y;
        insert(x);
        printf("%d\n",var.ask(ha[rt]));
    }
    return 0;
}

d1t3 成都七中

题意

给定一棵树,每个点有一个颜色,\(q\) 次查询,每次询问编号在 \([l,r]\) 中的节点保留,\(x\) 所在的连通块的颜色种类数
\(n,q\leq 10^5\)

题解

注意到一个联通块中一定有一个点,使得这个连通块中所有的点都在点分树上以这个点为根的子树中。
那么就可以把 \([l,r,x]\) 挂在这个点上,然后遍历点分树上的每一个点 \(p\),对于这个点分树子树中的每个点 \(q\) 求出他在原树上到 \(p\) 的路径上经过的节点编号的最小值和最大值 \(mn_q,mx_q\),那么一次询问相当于数矩形内的颜色数,直接按 \(mx\)\(r\) 排序,简单扫描线即可。

点击查看代码
#include <bits/stdc++.h>

using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

const int N=1e5+5;

# define ll long long
# define db double
# define ull unsigned long long
# define uint unsigned int
# define chkmax(a,b) a=max(a,b)
# define chkmin(a,b) a=min(a,b)
# define mkp make_pair
# define PII pair<int,int>
# define PLL pair<ll,ll>
# define PIL pair<int,ll>
# define PLI pair<ll,int>

template<typename T> void read(T &x){
    x=0;int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

int n,m;
int a[N];
int head[N],cnt;
int siz[N],mxsiz[N];
int p[N],totp;
int bit[N],mxl[N];
int out[N];
bool vis[N];

struct Edge{
    int to,next;
}e[N<<1];

void add(int x,int y){
    e[++cnt]=(Edge){y,head[x]},head[x]=cnt;
}

struct misaka{
    int l,r,id;
};

bool cmp(misaka x,misaka y){
    if(x.r!=y.r)return x.r<y.r;
    else return x.l<y.l;
}

vector<misaka> son[N],T[N],Q[N];

void upd(int l,int r,int x){
    for(int o=l;o<=n;o+=o&-o)bit[o]+=x;
    for(int o=r+1;o<=n;o+=o&-o)bit[o]-=x;
}

int ask(int o){
    int res=0;
    for(;o;o-=o&-o)res+=bit[o];
    return res;
}

void clear(int o){
    for(;o<=n;o+=o&-o)bit[o]=0;
}

void dfs1(int u,int fa){
    p[++totp]=u;
    siz[u]=1,mxsiz[u]=0;
    RepG(i,u){
        int v=e[i].to;
        if(v==fa||vis[v])continue;
        dfs1(v,u);
        siz[u]+=siz[v];
        chkmax(mxsiz[u],siz[v]);
    }
}

void dfs2(int u,int fa,int l,int r,int ff){
    chkmin(l,u),chkmax(r,u);
    son[ff].push_back((misaka){l,r,u});
    T[u].push_back((misaka){l,r,ff});
    RepG(i,u){
        int v=e[i].to;
        if(v==fa||vis[v])continue;
        dfs2(v,u,l,r,ff);
    }
}

void solve(int u,int ff){
    totp=0;
    dfs1(u,0);
    int rt=p[1];
    Rep(i,2,totp)if(max(mxsiz[p[i]],totp-siz[p[i]])<max(mxsiz[rt],totp-siz[rt]))rt=p[i];
    dfs2(rt,0,rt,rt,rt);
    vis[rt]=true;
    RepG(i,rt){
        int v=e[i].to;
        if(vis[v])continue;
        solve(v,rt);
    }
}   

int main()
{
    # ifndef ONLINE_JUDGE
    freopen("testdata.in","r",stdin);
    //freopen("test1.out","w",stdout);
    # endif
    memset(head,-1,sizeof(head));
    read(n),read(m);
    Rep(i,1,n)read(a[i]);
    Rep(i,1,n-1){
        int x,y;
        read(x),read(y);
        add(x,y),add(y,x);
    }
    solve(1,0);
    Rep(i,1,n)reverse(T[i].begin(),T[i].end());
    Rep(i,1,m){
        int l,r,x;
        read(l),read(r),read(x);
        int now=x;
        for(int j=0;j<T[x].size();j++)
            if(T[x][j].l>=l&&T[x][j].r<=r)now=T[x][j].id;
        Q[now].push_back((misaka){l,r,i});
    }
    Rep(i,1,n){
        sort(Q[i].begin(),Q[i].end(),cmp);
        sort(son[i].begin(),son[i].end(),cmp);
        int now=0;
        for(int j=0;j<Q[i].size();j++){
            while(now<son[i].size()&&son[i][now].r<=Q[i][j].r){
                if(mxl[a[son[i][now].id]]<son[i][now].l)
                    upd(mxl[a[son[i][now].id]]+1,son[i][now].l,1),mxl[a[son[i][now].id]]=son[i][now].l;
                now++;
            }
            out[Q[i][j].id]=ask(Q[i][j].l);
        }
        now=0;
        clear(1);
        for(int j=0;j<son[i].size();j++)mxl[a[son[i][j].id]]=0,clear(son[i][j].l),clear(son[i][j].l+1);
    }
    Rep(i,1,m)printf("%d\n",out[i]);
    return 0;
}

d2t1 竞赛实验班

题意

维护一个长度为 \(n\) 的序列,\(m\) 次操作

  • 在末尾插入 \(x\)
  • 询问区间和
  • 全局异或 \(x\)
  • 将数组 \(A\) 排序

\(n,m\leq 10^5\)

题解

首先不考虑最后一个操作,那么只需要 log 棵线段树维护每一位的值。
加上最后一个之后,我们可以发现一定是前面一段是有序的之后异或上一个 \(x\),后面一段是无序的。
后面一段就维护每一位的1的个数,前面部分拿一棵 trie 树维护,每个点维护其子树中每一位的1的个数。
异或直接记一个全局 tag,扫描 trie 树的时候根据 tag 看是先进左子树还是右子树。
每次排序就暴力把后半部分无序的暴力扔到 trie 里面即可

点击查看代码
#include <bits/stdc++.h>

using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

const int N=2e5+5;
const int M=N*30;

# define ll long long
# define db double
# define ull unsigned long long
# define uint unsigned int
# define chkmax(a,b) a=max(a,b)
# define chkmin(a,b) a=min(a,b)
# define mkp make_pair
# define PII pair<int,int>
# define PLL pair<ll,ll>
# define PIL pair<int,ll>
# define PLI pair<ll,int>

template<typename T> void read(T &x){
    x=0;int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

int n,q,now,tag,trietag;
int a[N],b[N][30];
int trie[M][2],siz[M];
int cnt[M][30],tot;
int res[30];

void insert(int x){
    int u=0;
    _Rep(i,29,0){
        int j=x>>i&1;
        if(!trie[u][j])trie[u][j]=++tot;
        u=trie[u][j],siz[u]++;
        Rep(j,0,29)cnt[u][j]+=x>>j&1;
    }
}

void query(int u,int bit,int k,int opt){
    if(bit==-1){
        Rep(j,0,29)if(cnt[u][j])res[j]+=opt*k;
        return;
    }
    int i=trietag>>bit&1;
    if(siz[trie[u][i]]<=k){
        Rep(j,0,29)res[j]+=opt*cnt[trie[u][i]][j];
        query(trie[u][i^1],bit-1,k-siz[trie[u][i]],opt);
    }
    else query(trie[u][i],bit-1,k,opt);
}

int main()
{
    # ifndef ONLINE_JUDGE
    freopen("testdata.in","r",stdin);
    //freopen("test1.out","w",stdout);
    # endif
    read(n);
    Rep(i,1,n)read(a[i]);
    Rep(i,1,n)Rep(j,0,29)b[i][j]=b[i-1][j]+(a[i]>>j&1);
    read(q);
    while(q--){
        int opt,x,y;
        read(opt);
        if(opt==1){
            read(x),x^=tag;
            a[++n]=x;
            Rep(j,0,29)b[n][j]=b[n-1][j]+(x>>j&1);
        }
        if(opt==2){
            Rep(j,0,29)res[j]=0;
            read(x),read(y);
            if(y<=now)query(0,29,y,1),query(0,29,x-1,-1);
            else if(x<=now){
                query(0,29,now,1),query(0,29,x-1,-1);
                Rep(j,0,29)res[j]+=b[y][j]-b[now][j];
            }
            else Rep(j,0,29)res[j]=b[y][j]-b[x-1][j];
            ll ans=0;
            Rep(j,0,29)
                if(tag>>j&1)ans+=(y-x+1-res[j])*(1ll<<j);
                else ans+=res[j]*(1ll<<j);
            printf("%lld\n",ans);
        }
        if(opt==3)read(x),tag^=x;
        if(opt==4){
            trietag=tag;
            Rep(i,now+1,n)insert(a[i]);
            now=n;
        }
    }
    return 0;
}

d2t2 WBLT

题意

不好说

题解

对于 \(b\geq B\),莫队维护区间 bitset,然后每 \(b\) 个分裂出一块,然后 and 一下,复杂度是 \(O(m\times \dfrac{n}{b}\dfrac{b}{w})=O(\dfrac{nm}{w})\)
对于每个 \(b<B\) 分开处理,对于每一个 \(\bmod b\) 的余数开一个 bitset,每次 findfirst0,复杂度 \(O(mb\times \dfrac{n}{bw})=O(\dfrac{nm}{w})\)
\(B=64\) 或者 \(128\) 比较优秀。
为什么要分两种是因为实际上除法是向上取整,这两种做法向上取整的位置不太一样。
需要手写 bitset。

点击查看代码
#include <bits/stdc++.h>

using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

const int N=1e5+5;
const int sak=64;

# define ll long long
# define db double
# define ull unsigned long long
# define uint unsigned int
# define chkmax(a,b) a=max(a,b)
# define chkmin(a,b) a=min(a,b)
# define mkp make_pair
# define PII pair<int,int>
# define PLL pair<ll,ll>
# define PIL pair<int,ll>
# define PLI pair<ll,int>

const int Mxdt = (1<<16);inline char pc(char ch,bool bj){	static char buf[Mxdt],*p1=buf,*p2=buf+Mxdt;	return ((bj)||(*p1++=ch)&&p1==p2)&&fwrite(p1=buf,1,p1-buf,stdout),0;}void print(int x){	if(x>9)print(x/10);	pc(x%10^48,false);}inline void printnum(int x,int ch){	if(x < 0)pc('-',false),x=-x;	print(x),pc(ch,false);}
char gc()
{
	static char buf[1<<16],*S,*T;
	if(T==S)
	{
		T=(S=buf)+fread(buf,1,1<<16,stdin);
		if(T==S) return EOF;
	}
	return *S++;
}
#define getchar gc

template<typename T> void read(T &x){
    x=0;int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

int n,m,B,BB;
int a[N];
int pos[N];
int cnt[N];
int out[N];
ull low[64];

struct misaka{
    int l,r,b,id;
    bool operator < (const misaka &cmp)const{
        if(pos[l]!=pos[cmp.l])return pos[l]<pos[cmp.l];
        else if(pos[l]&1)return r<cmp.r;
        else return r>cmp.r;
    }
}q1[N];

vector<misaka> q2[sak];
int totq;

struct Bitset{
    vector<ull> a;
    int siz;
    void clear(){for(int i=0;i<siz;i++)a[i]=0;}
    void init(int len){a.resize(len/64+1),siz=a.size();clear();}
    void set(int x){a[x>>6]|=(1ull<<(x&63));}
    void reset(int x){a[x>>6]&=~(1ull<<(x&63));}
    void flip(){for(int i=0;i<siz;i++)a[i]=~a[i];}
    bool empty(){for(int i=0;i<siz;i++)if(a[i])return false;return true;}
    int findfirst0(){for(int i=0;i<siz;i++)if(~a[i])for(int j=0;j<64;j++)if(a[i]>>j&1^1)return i*64+j;}
    void operator &=(const Bitset &x){for(int i=0;i<siz;i++)a[i]&=x.a[i];}
};

Bitset S,Sp[1600],res;

void split(int B){
    int all=100001/B+2;
    for(int i=0;i<=all;i++)Sp[i].init(B);
    int k=Sp[0].siz-1,b=B&63,delta=0,now=0,id=0;
    for(int i=0;i<S.siz;i++,now++)
        if(now==k){
            if(!b)i--;
            else if(delta+b<=63)Sp[id].a[now]=(S.a[i]>>delta)&low[b-1],i--;
            else if(delta+b==64)Sp[id].a[now]=S.a[i]>>delta;
            else if(i!=S.siz-1)Sp[id].a[now]=(S.a[i]>>delta)^((S.a[i+1]&low[delta+b-65])<<64-delta);
            else Sp[id].a[now]=S.a[i]>>delta;
            delta=(delta+b)%64,id++,now=-1;
        }
        else{
            if(delta==0)Sp[id].a[now]=S.a[i];
            else if(i!=S.siz-1)Sp[id].a[now]=(S.a[i]>>delta)^((S.a[i+1]&low[delta-1])<<64-delta);
            else Sp[id].a[now]=S.a[i]>>delta;
        }
}

void add1(int x){cnt[a[x]]++;if(cnt[a[x]]==1)S.set(a[x]);}
void del1(int x){cnt[a[x]]--;if(cnt[a[x]]==0)S.reset(a[x]);}
void add2(int x){cnt[a[x]]++;if(cnt[a[x]]==1)Sp[a[x]%BB].set(a[x]/BB);}
void del2(int x){cnt[a[x]]--;if(cnt[a[x]]==0)Sp[a[x]%BB].reset(a[x]/BB);}

int main()
{
    # ifndef ONLINE_JUDGE
    freopen("testdata.in","r",stdin);
    //freopen("test1.out","w",stdout);
    # endif
    low[0]=1;
    for(int i=1;i<63;i++)low[i]=low[i-1]<<1|1;
    read(n);
    Rep(i,1,n)read(a[i]);
    read(m);
    Rep(i,1,m){
        int l,r,b;
        read(l),read(r),read(b);
        if(b<sak)q2[b].push_back((misaka){l,r,b,i});
        else q1[++totq]=(misaka){l,r,b,i};
    }  
    B=n/sqrt(totq+1)+1;
    Rep(i,1,n)pos[i]=(i-1)/B+1;
    sort(q1+1,q1+totq+1);
    S.init(100002);
    for(int i=1,l=1,r=0;i<=totq;i++){
        while(l>q1[i].l)add1(--l);
        while(r<q1[i].r)add1(++r);
        while(l<q1[i].l)del1(l++);
        while(r>q1[i].r)del1(r--);
        split(q1[i].b);
        res.init(q1[i].b),res.flip();
        for(int j=0;;j++){
            res&=Sp[j];
            if(res.empty()){out[q1[i].id]=j;break;}
        }
    }
    for(int b=1;b<sak;b++){
        if(!q2[b].size())continue;BB=b;
        memset(cnt,0,sizeof(cnt));
        B=n/sqrt((int)q2[b].size())+1;
        Rep(i,1,n)pos[i]=(i-1)/B+1;
        sort(q2[b].begin(),q2[b].end());
        for(int j=0;j<b;j++)Sp[j].init(100002/b+1);
        for(int i=0,l=1,r=0;i<q2[b].size();i++){
            while(l>q2[b][i].l)add2(--l);
            while(r<q2[b][i].r)add2(++r);
            while(l<q2[b][i].l)del2(l++);
            while(r>q2[b][i].r)del2(r--);
            for(int j=0;j<b;j++)chkmax(out[q2[b][i].id],Sp[j].findfirst0());
        }
    }
    Rep(i,1,m)printf("%d\n",out[i]);
    return 0;
}
posted @ 2022-12-03 16:17  YuukiYumesaki  阅读(47)  评论(0编辑  收藏  举报